Multi-File Editing and Refactoring
Multi-File Editing and Refactoring
Real development tasks rarely touch a single file. Renaming a component means updating the component file, every file that imports it, and maybe tests and docs. Changing an API means updating the route handler, the client code, the types, and the tests. Adding a feature across a layered app touches the database, the service layer, and the UI.
Before AI editors, this meant a fragile project-wide find-and-replace or careful manual work across a dozen open files. In Cursor, it's a job for the agent: you describe the change in plain English, and the agent finds the files, edits them, and can run your tests. For bigger changes, you plan first with Plan mode, then build with Agent mode.
What You'll Learn
- How Agent mode makes coordinated multi-file edits
- Using Plan mode to design a big refactor before any code changes
- How to phrase multi-file requests
- Reviewing diffs and accepting or rejecting changes
- Common multi-file tasks and how to approach them
- Using
@mentions to scope edits - Checkpoints, git, and reverting changes
- Running work in parallel with worktrees
- Best practices for large refactors
One Agent, Different Modes
Older versions of Cursor had a separate "Composer" panel for multi-file edits. That panel no longer exists. Its abilities were merged into the agent, which lives in the Agent side panel (Cmd+I or Cmd+L on macOS, Ctrl+I or Ctrl+L on Windows/Linux). Today "Composer" is the name of Cursor's own coding model, not a panel.
You switch modes with Shift+Tab in the chat input or with the mode picker. For multi-file work, two modes matter most:
- Agent (the default) reads and edits files, runs terminal commands, and searches your codebase on its own. It's how changes actually get made.
- Plan researches your codebase, asks clarifying questions, and writes an editable plan. Nothing is built until you approve it. Use it for complex, multi-file, or architectural changes, or when the requirements are still fuzzy.
Ask mode (read-only) is also handy for exploring before you decide what to change.
Plan First, Then Build
For anything bigger than a few files, start in Plan mode:
(Plan mode)
I want to migrate all API calls from fetch() to Axios. Find every
call site, note any custom error handling, and propose a step-by-step
plan. Ask me about anything that is unclear.
The agent explores the project, may ask questions ("Should the retry logic in api/client.ts be kept?"), and then writes a plan listing the files and steps. Read it carefully. You can edit the plan directly: remove steps, add constraints, or reorder the work.
When the plan looks right, build from it. The agent then works through the steps in Agent mode. Catching a misunderstanding in a plan is far cheaper than unpicking it from a 30-file diff.
How to Request Multi-File Changes
Specific requests get good results. Vague requests get vague results.
A Structure That Works
[Context about the current state]
[What you want to change]
[Any constraints or conventions to follow]
For example:
@components/Button.tsx @components/Card.tsx @components/Modal.tsx
These components use inline style objects for sizing. Refactor
them to use Tailwind utility classes. Follow the pattern in
@components/Badge.tsx, which has already been migrated.
When you don't know which files are affected, just say so. The agent will search:
Rename the UserProfile component to AccountProfile. Update the
component file, all imports, and any tests that reference it.
Pointing to a reference file that already follows the target pattern is one of the best ways to improve results.
Reviewing Multi-File Diffs
As the agent edits, each change shows up as a diff in the editor (green for additions, red for removals), and the changed files are listed in the chat. Review them before you accept. Accepting changes blindly is how subtle bugs slip in.
You can:
- Open each changed file and read the diff
- Accept or reject changes file by file, or hunk by hunk
- Accept all changes with
Cmd+Return(Ctrl+Enter) - Reject all changes with
Cmd+Shift+Backspace(Ctrl+Shift+Backspace) - Ask follow-ups: "Why did you also change the test file?"
- Ask for corrections: "The change to utils/api.ts is wrong. Revert just that file and try again."
Review every file, including ones you didn't expect to change. Sometimes the agent spotted something you missed. Sometimes it over-applied a pattern. Either way, you want to know.
What to Look For
- Correct intent: Does each change do what you asked?
- Consistency: For a rename, is every reference updated?
- Side effects: Did the agent change anything you didn't ask for?
- Tests: Were tests updated, and do they pass?
- Types: In TypeScript, do the signatures still match?
Common Multi-File Tasks
Renaming a Component
A rename usually touches the component file (name and export), every importing file, tests, and sometimes style files.
Rename the component UserCard to MemberCard. Include the file
itself (UserCard.tsx → MemberCard.tsx), the function name, all
imports, and all test references. Keep all props and logic.
Updating an API and Its Callers
@api/users/route.ts @hooks/useUser.ts @components/UserSettings.tsx
The API response now includes a `preferences` object next to the
existing `profile` object. Update the route handler to return it,
the useUser hook to expose it, and UserSettings to display it.
Adding a Feature Across Layers
This is a good fit for Plan mode:
(Plan mode)
I want to add a "featured" boolean flag to products.
1. Add the field to the database schema (schema.ts)
2. Update the queries to include it in reads and writes
3. Update the API response types
4. Add a toggle to the product admin form
5. Show a "Featured" badge on the product card
Follow any existing boolean flag for the pattern.
Numbered steps make it less likely that the agent skips one.
Fixing Imports After Moving Files
I just moved all utility files from src/utils/ to src/lib/utils/.
Update every import that references the old path, then run the
type checker to confirm nothing is broken.
Because Agent mode can run terminal commands, you can ask it to verify its own work with your type checker or test suite.
Adding a Required Parameter
I'm adding a required `tenantId: string` parameter to `createUser`
in src/services/UserService.ts. Find every call and pass the right
tenantId. It comes from the request context in API routes and from
the session in server components.
Using @ Mentions to Scope Edits
Mentions don't just add context. They also tell the agent which files are in play.
# Too open-ended: the agent might change many files you didn't expect
Update the error handling to use the new AppError class.
# Better scoped: changes stay in these three files
@services/OrderService.ts @services/PaymentService.ts @services/EmailService.ts
Update the error handling in only these three files to use the
AppError class from @utils/errors.ts instead of plain Error objects.
A practical approach: let the agent (or Ask mode) find the affected files first, then mention the ones you want changed.
Checkpoints and Reverting Changes
Protect yourself with two safety nets: git commits and Cursor's checkpoints.
Commit Before You Start
git add -A && git commit -m "WIP: before refactor of auth system"
If the refactor goes badly, git restore . throws away the edits to existing files, and git clean -fd deletes any new files the agent created (preview them first with git clean -nd). Together they take you back to that commit. No Cursor features needed.
Cursor Checkpoints
Cursor creates checkpoints as the agent works. Click any checkpoint in the chat timeline to preview your files as they were at that point, then restore it to revert every file back to that state. This is great for undoing a bad turn in the conversation without losing the whole session.
Checkpoints are a convenience, not a replacement for git. Keep committing at good stopping points.
Reverting a Single File
To undo one file without touching the rest:
- Before accepting, reject the changes in just that file
- After accepting, restore it with git:
git checkout HEAD -- src/components/OrderForm.tsx
Or use the Source Control panel: right-click the file and choose "Discard Changes".
When to Stop and Start Fresh
Signs a refactor has gone off track:
- The diff keeps growing but looks less and less correct
- The agent is fixing problems it created a few steps earlier
- The chat is so long that the same mistakes keep coming back
When this happens, reject all changes (or restore a checkpoint), make sure you are on a clean commit, and start a new chat with a more focused request. Plan mode is a good way to restart.
Running Work in Parallel
For larger efforts, Cursor can run more than one agent at a time. The Agents Window lets you run several agents in parallel, including in separate git worktrees, so each agent works on its own copy of the code without stepping on the others. The /worktree command starts a task in a worktree, and /best-of-n runs the same task several times so you can pick the best result.
This is useful when you want to try two approaches to a refactor side by side, or split independent changes between agents. For a first refactor, though, one agent in the editor is plenty. These features change often, so check the Cursor docs for the current options.
Best Practices for Large Refactors
Start Small, Then Scale
Don't ask for everything at once. Start with one representative file:
@src/services/UserService.ts
Refactor this file to use the Repository pattern. Do not change
any other files yet.
Review the result. If it's right, ask the agent to apply the same pattern to the other service files. If it's wrong, fix it on one file before the mistake spreads.
Use Tests as a Safety Net
Rename UserProfile to AccountProfile across the codebase. When
you're done, run `npm test` and fix anything that fails.
Passing tests before and after a refactor are more reassuring than reading every diff line, though you should still review the diff.
Say What Should Not Change
@services/ProductService.ts
Refactor the data fetching to use React Query. Do NOT change the
props interface or the business logic in the service methods.
Only the data fetching layer.
Clear boundaries stop the agent from making "improvements" you didn't ask for.
Break Large Tasks Into Phases
For refactors that touch dozens of files, work in phases and commit after each:
- Phase 1: Update the core module (one file, careful review)
- Phase 2: Update direct callers (a few files, focused diff)
- Phase 3: Update tests (easy to verify)
- Phase 4: Update docs (low risk)
A Plan mode plan maps naturally onto these phases. Committing after each one means you can always roll back to a clean middle state.
Key Takeaways
- There is no separate Composer panel anymore. Multi-file edits happen in the Agent side panel, and "Composer" is now the name of Cursor's own model.
- Use Plan mode for big or unclear changes: the agent researches, asks questions, and writes an editable plan before building in Agent mode.
- Good requests describe the current state, the change, and the constraints. A reference file that already follows the pattern helps a lot.
- Review every changed file. Accept or reject per file, or all at once with
Cmd+ReturnandCmd+Shift+Backspace(Ctrl+EnterandCtrl+Shift+Backspaceon Windows and Linux). - Use
@mentions to limit which files the agent changes. - Commit before large refactors. Use checkpoints to roll back a bad turn, and git to revert individual files.
- For bigger efforts, the Agents Window and worktrees let you run agents in parallel.
- Start with one file, verify the pattern, then scale. Let the agent run your tests between phases.

