AI Tools Compared

If you have been using GitHub Copilot with custom instructions and want to switch to Cursor, you need to understand how to migrate your configuration. Both tools use configuration files to customize AI behavior, but the formats differ significantly. This guide walks you through converting Copilot custom instructions into Cursor rules files, with practical examples and common conversion patterns.

Key Differences Between Copilot and Cursor Configuration

GitHub Copilot stores custom instructions in your VSCode settings under github.copilot.chat.instructions. The setting accepts a single string containing your guidelines. Cursor, on the other hand, uses .cursorrules files that support structured YAML-like syntax with distinct sections for different types of instructions.

Copilot custom instructions work as flat text guidelines that Copilot appends to its system prompt. Cursor rules files provide more organization, allowing you to define separate rules for code generation, chat behavior, file handling, and project-specific conventions.

Finding Your Copilot Custom Instructions

Before migrating, locate your existing Copilot configuration. In VSCode, go to Settings and search for “Chat: Instructions” under GitHub Copilot Chat. You can also check your .vscode/settings.json file directly:

{
  "github.copilot.chat.instructions": "Your custom instructions here"
}

Copy this content somewhere safe. You will transform this into Cursor’s format.

Converting Basic Guidelines

The simplest conversion involves taking your plain text instructions and structuring them for Cursor. Here is an example of converting a Copilot instruction to Cursor format.

Copilot custom instruction:

Always use const instead of let unless variable reassignment is needed. Use async/await over Promise chains. Add JSDoc comments to all exported functions.

Cursor rules file (.cursorrules):

rules:
  - description: "Prefer const over let"
    rule: |
      Always use const for variable declarations. Only use let when the variable must be reassigned later.
      Never use var.
  - description: "Use async/await syntax"
    rule: |
      Prefer async/await over Promise.then() and Promise.catch() chains.
      Write cleaner asynchronous code using await instead of nested Promise callbacks.
  - description: "Document exported functions"
    rule: |
      Add JSDoc comments to all exported functions. Include @param, @returns,
      and @throws tags where applicable.

Handling Project-Specific Rules

If your Copilot instructions include project-specific guidelines, you can express these in Cursor’s project context section. Cursor supports defining rules that apply only to specific file types or directories.

Copilot instruction for a React project:

When creating React components, use functional components with hooks. Always use TypeScript. Name components using PascalCase.

Cursor rules for the same:

project:
  name: "My React Application"
  type: "webapp"

fileRules:
  - pattern: "**/*.tsx"
    rules:
      - description: "Use functional components"
        rule: |
          Create React components as functional components using hooks.
          Avoid class components unless required by external libraries.
      - description: "Component naming"
        rule: |
          Name component files using PascalCase (e.g., UserProfile.tsx).
          Export components as default when the file contains only one component.

Migrating Code Style Preferences

Code style rules often form the bulk of custom instructions. Cursor handles these more elegantly with its linting integration and automatic formatting awareness.

Copilot instruction:

Use 2 spaces for indentation. Always use single quotes for strings in JavaScript. Add trailing commas in multiline objects and arrays.

Cursor rules:

codeStyle:
  indentation: 2
  quoteStyle: "single"
  trailingCommas: true

linting:
  preferESLint: true
  autoFixOnSave: true

Including Example Code

Cursor rules files support embedding example code snippets, which helps the AI understand your expected output format. This was difficult to express in Copilot’s flat instruction format.

Cursor rules with examples:

rules:
  - description: "API response format"
    rule: |
      All API endpoints must return responses in this format:

      ```typescript
      interface ApiResponse<T> {
        data: T;
        success: boolean;
        message?: string;
        errors?: string[];
      }
      ```

      Use this interface for every controller response.

Defining File Ignore Patterns

Cursor lets you specify which files the AI should ignore or treat differently. This is useful for excluding generated files, node_modules, or build artifacts from AI analysis.

Cursor ignore rules:

ignore:
  - "**/node_modules/**"
  - "**/dist/**"
  - "**/build/**"
  - "**/*.min.js"
  - "**/coverage/**"
  - ".git/**"

Creating Multiple Rule Files

Cursor supports organizing rules across multiple files. You can create a base .cursorrules file in your project root and additional rule files for specific purposes or modules.

Common organization:

Reference these files in your main configuration:

extends:
  - ".cursorrules.tests"
  - ".cursorrules.api"

Testing Your Migrated Rules

After converting your instructions, test the new rules by asking Cursor to generate code that should follow your guidelines. Verify that:

  1. Code follows your style preferences
  2. Project-specific patterns are respected
  3. File type rules apply correctly
  4. Ignored files are not processed by the AI

If something does not work as expected, adjust the rules and test again. Cursor’s rule system is more powerful than Copilot’s but requires more precise formatting.

Common Conversion Mistakes to Avoid

When migrating, watch for these common issues:

Problem: Putting too much in a single rule.

Solution: Break complex guidelines into multiple smaller rules with clear descriptions.

Problem: Using Copilot-specific terminology.

Solution: Replace references to “Copilot” with generic AI assistant terms that work with any tool.

Problem: Forgetting to escape special characters.

Solution: In YAML, special characters like :, {, }, and [ need proper escaping or quoting.

Summary

Converting Copilot custom instructions to Cursor rules files requires restructuring your guidelines into YAML format with distinct sections. The process involves locating your current Copilot settings, converting plain text instructions into structured rules, adding Cursor-specific features like file ignore patterns and example code, and testing the new configuration thoroughly.

Cursor’s rule system offers more organizational options than Copilot’s simple string-based instructions. Take advantage of multiple rule files, file type specificity, and example embedding to get the most out of your migration.

Advanced Cursor Rules Configuration

Once you understand basic migration patterns, you can use Cursor’s more sophisticated capabilities.

Dynamic Rules Based on File Context

Cursor supports rules that apply differently based on file type, directory, or project context.

# .cursorrules

rules:
  - description: "General coding standards"
    rule: |
      All code should follow these principles:
      - Single responsibility principle
      - DRY (Don't Repeat Yourself)
      - Clear naming conventions

# File type specific rules
fileRules:
  - pattern: "**/*.ts"
    rules:
      - description: "TypeScript strict mode"
        rule: |
          All TypeScript files must:
          - Use strict: true in tsconfig
          - Add explicit return types to all functions
          - Use interfaces for object types, never implicit any
          - Use readonly where appropriate for immutability

  - pattern: "**/*.test.ts"
    rules:
      - description: "Test-specific conventions"
        rule: |
          Test files should:
          - Use descriptive test names that explain the scenario
          - Group related tests in describe blocks
          - Mock external dependencies, never make real HTTP calls
          - Include both happy path and error case tests

  - pattern: "src/api/**/*.ts"
    rules:
      - description: "API endpoint conventions"
        rule: |
          API endpoints must:
          - Validate all input parameters
          - Return consistent response format
          - Include appropriate HTTP status codes
          - Log all requests and errors
          - Handle errors gracefully with descriptive messages

# Directory-specific architecture rules
directoryRules:
  - path: "src/components"
    rules:
      - description: "React component standards"
        rule: |
          React components must:
          - Be functional components using hooks
          - Include PropTypes or TypeScript interfaces
          - Export as default for simple components
          - Include JSDoc comments for component purpose
          - Be under 300 lines maximum

  - path: "src/utils"
    rules:
      - description: "Utility function standards"
        rule: |
          Utility functions should:
          - Have single, well-defined purpose
          - Include comprehensive docstrings
          - Be pure functions when possible
          - Handle edge cases explicitly
          - Include examples in docstrings

This structure replaces Copilot’s flat instructions with precise, contextual guidance that Cursor applies automatically.

Custom Rule Syntax and Inheritance

For large projects or teams, inherit from base rules and extend them. Create a main .cursorrules file with company-wide standards, then create specialized .cursorrules.react, .cursorrules.api, etc. files that extend the base rules with domain-specific guidance.

Rule Enforcement with Examples

Make rules more effective by including concrete examples Cursor can reference:

rules:
  - description: "Error handling pattern"
    rule: |
      Use async/await with try-catch for error handling.

      **GOOD:**
      ```typescript
      async function fetchUser(id: string) {
        try {
          const response = await fetch(`/api/users/${id}`);
          if (!response.ok) throw new Error('Not found');
          return response.json();
        } catch (error) {
          console.error('Failed to fetch user:', error);
          throw error;
        }
      }
      ```

      **BAD:**
      ```typescript
      function fetchUser(id: string) {
        return fetch(`/api/users/${id}`)
          .then(res => res.json())
          .catch(err => console.log(err));
      }
      ```

      Always include catch blocks. Always log errors. Always propagate critical errors.

  - description: "Component state management"
    rule: |
      Use state management appropriate to component complexity.

      For simple state (< 3 state variables): useState is fine
      For complex state (> 3 variables): useReducer provides clarity
      For shared state across many components: Context API or state library

      **GOOD (simple state):**
      ```typescript
      const UserForm = () => {
        const [name, setName] = useState('');
        const [email, setEmail] = useState('');
        // ...
      };
      ```

      **GOOD (complex state):**
      ```typescript
      type FormState = { name: string; email: string; phone: string; };
      type FormAction = { type: 'setName'; value: string } | { type: 'reset' };

      const reducer = (state: FormState, action: FormAction): FormState => {
        // ...
      };

      const UserForm = () => {
        const [state, dispatch] = useReducer(reducer, initialState);
        // ...
      };
      ```

Performance Optimization in Rules

For developers concerned about performance, include specific Cursor rule guidance:

rules:
  - description: "Render performance"
    rule: |
      Prevent unnecessary re-renders:

      - Memoize expensive computations with useMemo
      - Wrap callbacks with useCallback if passed to child components
      - Use React.memo for pure components
      - Consider useTransition for non-blocking state updates

      When to optimize: Profile first with React DevTools. Only optimize
      after identifying actual performance bottlenecks.

  - description: "Bundle size awareness"
    rule: |
      Keep bundle size manageable:

      - Avoid importing entire libraries when you only need one function
      - Use dynamic imports for large optional features
      - Check bundle impact before adding new dependencies

      Good: `import { debounce } from 'lodash-es'`
      Bad: `import _ from 'lodash'`

Integrating Rules Across Your Team

When rolling out Cursor rules across a team, start with minimal rules focused on your most important conventions. Get team feedback after a week of use, then iterate based on what works in practice. Document the rationale for each rule—explain WHY each convention exists, not just WHAT. This helps developers understand and internalize the conventions.

Built by theluckystrike — More at zovo.one