Edit 50 Files in Cursor Composer Without Breaking Code

Master Cursor's Composer Mode to safely refactor across multiple files with AI assistance and automatic context management.

Problem: Refactoring Breaks Everything Across Files

You need to rename a function used in 30 files, update API endpoints across your codebase, or migrate to a new library. Traditional find-and-replace is too risky, and manual editing takes hours.

You'll learn:

  • How Composer Mode manages multi-file context automatically
  • Safe workflows for large-scale refactoring
  • When to use Composer vs Chat mode
  • Recovery strategies when AI makes mistakes

Time: 12 min | Level: Intermediate


Why Manual Multi-File Editing Fails

Traditional IDEs force you to:

  • Manually track which files need changes
  • Remember context when switching between files
  • Hope find-and-replace catches all cases
  • Manually verify nothing broke

Common failures:

  • Missed edge cases in conditional imports
  • Breaking changes in test files
  • Type errors cascading across modules
  • Git conflicts from simultaneous edits

Cursor's Composer Mode solves this by maintaining awareness of your entire codebase while making coordinated changes.


Solution

Step 1: Enable Composer Mode

# Open Cursor (install from cursor.sh if needed)
# Keyboard shortcut
Cmd+I (Mac) or Ctrl+I (Windows/Linux)

You'll see: A split-pane interface with:

  • Left: Your file tree and editor
  • Right: Composer chat panel
  • Bottom: File selection pills showing context

Expected: Composer starts with files you have open already included in context.


Step 2: Add Files to Context Strategically

Composer Mode automatically includes:

  • Currently open files
  • Files referenced in your prompt
  • Related files based on imports

Manually add files:

# In Composer, use @ to search files
@src/utils/api.ts @src/components/UserList.tsx

# Or reference by pattern
@**/*.test.ts  # All test files

Why this works: Cursor's AI understands file relationships. Adding the entry point (like api.ts) often auto-includes dependents.

Best practice: Start with 5-10 core files. Composer will suggest adding more if needed.


Step 3: Write Specific Refactoring Instructions

# ✅ Good: Specific with constraints
Rename function `fetchUser` to `getUserById` across all files. 
Update imports and add JSDoc. Don't change test assertions.

# ⌠Bad: Vague and risky  
Update the user functions to be better

Template for large changes:

Task: [What to change]
Scope: [Which files/patterns]
Preserve: [What NOT to change]
Verify: [How to test]

Example:
Task: Migrate from axios to fetch API
Scope: All files in src/api/*.ts
Preserve: Error handling structure, retry logic
Verify: npm test && curl localhost:3000/health

If Composer asks questions: It needs more context. Add the files it requests or clarify constraints.


Step 4: Review Changes Before Applying

Composer shows a diff view for each file:

// src/api/users.ts
- export async function fetchUser(id: string) {
+ export async function getUserById(id: string) {
    const response = await fetch(`/api/users/${id}`);
    return response.json();
  }

Check for:

  • Changed only what you asked for
  • Didn't modify comments with old function name
  • Updated imports in other files
  • Test files reflect new names

Red flags:

  • Removing error handling you didn't mention
  • Changing unrelated formatting
  • Adding dependencies you didn't request

Fix issues: Click "Edit" on specific file diffs to refine, or add constraint in Composer:

You removed the try-catch in api.ts. Keep all error handling.

Step 5: Apply and Verify

# Composer applies changes to working directory
# Immediately run tests
npm test

# Check TypeScript compilation
npm run type-check

# Git diff to see full scope
git diff --stat

You should see:

  • All tests passing
  • No new TypeScript errors
  • Git shows only expected files changed

If tests fail:

  • Type errors in 1-2 files: Use Composer to fix: "Fix TypeScript errors in @src/utils/api.ts"
  • Many failures: Undo with git checkout . and refine prompt with stricter constraints
  • Subtle bugs: Add failing test to context and ask Composer to fix

Step 6: Commit Atomically

# Composer changes are unstaged
git add -p  # Review each hunk

# Separate logical changes
git commit -m "refactor: rename fetchUser to getUserById"
git commit -m "test: update assertions for getUserById"

Why this matters: If you need to revert, atomic commits let you undo just the breaking part.


Advanced Workflows

Migrate 50 Components to New API

# Composer prompt
Migrate all components in @src/components/**/*.tsx from:
- Old: useQuery hook from react-query
- New: useSWR from swr

Keep same loading/error states. Update imports. 
Add @src/components/UserList.tsx as reference implementation.

Strategy:

  1. Add 1 completed migration as reference (UserList.tsx)
  2. Let Composer pattern-match across remaining files
  3. Review in batches of 10 files

Update Environment Variables Across Services

# Add config files to context
@apps/api/.env.example @apps/web/.env.example @docker-compose.yml

Rename POSTGRES_URL to DATABASE_URL everywhere.
Update TypeScript types in @packages/env/src/index.ts

Critical: Always include type definition files to ensure type safety.


Fix Security Vulnerability in 30 Dependencies

@package.json @pnpm-lock.yaml @**/package.json

Upgrade lodash from 4.17.19 to 4.17.21 in all workspaces.
Run pnpm install after. Show me the upgrade plan first.

Safety: Ask for plan before execution on dependency changes.


When NOT to Use Composer

Use regular Chat mode for:

  • Exploratory questions ("How does auth work?")
  • Single file changes under 50 lines
  • Code review without modification
  • Explaining existing code

Use manual editing for:

  • Formatting-only changes (use Prettier)
  • Find-and-replace of strings (use IDE)
  • Reverting changes (use git)

Composer excels at:

  • Cross-file refactoring (5+ files)
  • API migrations
  • Updating patterns across codebase
  • Adding features that touch multiple layers

Verification Checklist

After any Composer session:

# 1. Type safety
npm run type-check
# or
tsc --noEmit

# 2. Tests
npm test

# 3. Linting
npm run lint

# 4. Build
npm run build

# 5. Git sanity check
git diff --stat
git diff --name-only | wc -l  # Should match expected file count

Smoke test critical paths:

# Start dev server
npm run dev

# Test main user flows manually
# - Login
# - Core feature
# - Error states

Common Pitfalls and Fixes

"Composer Changed Too Much"

Problem: Asked to rename function, it refactored entire module structure.

Fix: Be more explicit:

Only rename the function. Don't restructure imports or 
add new abstractions. Preserve all existing patterns.

"Some Files Weren't Updated"

Problem: Function still has old name in 5 files.

Solution: Composer missed files not in context.

# Find remaining references
grep -r "fetchUser" src/

# Add missed files explicitly
@src/legacy/user-service.ts @tests/integration/auth.test.ts

Update fetchUser to getUserById in these files too

"Changes Broke Tests"

Problem: Refactoring changed behavior, not just names.

Fix: Add test files to context upfront:

@src/api/users.ts @src/api/users.test.ts

Rename fetchUser to getUserById. Update test descriptions 
but don't change assertions or mock data.

"Lost Track of What Changed"

Problem: Applied changes, now unsure what's different.

Prevention:

# Before using Composer
git commit -m "checkpoint before refactor"

# After Composer
git diff HEAD --stat  # See what changed from checkpoint

What You Learned

  • Composer Mode maintains multi-file context automatically
  • Start with specific constraints to avoid over-refactoring
  • Always verify with tests + type-check + git diff
  • Add reference implementations for pattern matching
  • Use atomic commits for easier rollback

Limitation: Composer works best with codebases under 500 files. Larger monorepos may need scoped workspaces.

When to upgrade workflow:

  • If changing >100 files regularly: Add pre-commit hooks
  • If team uses Composer: Establish review process for AI changes
  • If critical system: Require manual review of all diffs

Real-World Example: Migrating Auth Library

# Actual Composer prompt that worked

Task: Migrate from passport.js to @auth/core
Scope: @src/auth/*.ts @src/middleware/auth.ts @src/routes/api/*.ts
Reference: @src/auth/new-auth-example.ts (completed migration)

Preserve:
- All existing route paths
- Session cookie names  
- Error messages
- Rate limiting logic

Steps:
1. Update auth initialization in @src/auth/config.ts
2. Replace passport middleware with @auth/core adapters
3. Update route handlers to use new session API
4. Keep all existing tests passing - only update auth calls

Verify with: npm test && curl -X POST localhost:3000/api/login

Result: 23 files changed, 0 tests broken, deployed same day.

Key success factors:

  • Included working example file
  • Explicit preservation rules
  • Clear verification steps

Troubleshooting Quick Reference

SymptomLikely CauseFix
Composer ignores filesNot in contextAdd with @filename
Too many changesVague promptAdd "Only change X, preserve Y"
Type errorsMissing type filesAdd @**/*.d.ts to context
Tests failBehavior changedRollback, add tests to context, retry
Slow responsesToo many filesSplit into batches of 10-15
Lost changesForgot to applyCheck Composer panel for "Apply" button

Tested on Cursor 0.43.0, TypeScript 5.5+, Node.js 22.x

Note: Cursor Composer uses Claude Sonnet 4.5 by default. For very large refactors (100+ files), consider splitting into multiple sessions to stay within context limits.