Multi-File Workflows
You need to rename a field that’s threaded through a dozen files — the model, the service, three controllers, the migration, the API contract, and a wall of tests. Do it by hand and you’ll miss two callers and ship a 500. This is exactly the kind of change Claude Code is built for: it traces the dependency graph, edits every file consistently, and updates the tests in the same pass. The trick is knowing how to drive it so it stays accurate across the whole blast radius.
What You’ll Walk Away With
Section titled “What You’ll Walk Away With”- A plan-first prompt that forces Claude to map the blast radius before it touches a single file
- A repeatable pattern for safe, backward-compatible field and API renames
- Copy-paste prompts for cross-cutting refactors (extract shared logic, type propagation, dependency tracing)
- The real way to run independent multi-file tasks in parallel using git worktrees
- A recovery playbook for when a multi-file edit goes wrong mid-flight
Plan Before You Touch Code
Section titled “Plan Before You Touch Code”The single biggest accuracy win on multi-file changes is to separate planning from editing. Run Claude in plan mode first (claude --permission-mode plan, or press Shift+Tab to toggle into it), let it explore and propose, then approve before any file is written.
-
Ask for the change plan, not the change. Claude explores the codebase and reports what it intends to touch — without editing.
-
Review the blast radius. You’ll catch missing files or wrong assumptions here, where they’re free to fix, instead of in a diff of 40 files.
-
Refine, then approve. Add anything it missed, then let it execute the approved plan one layer at a time.
Plan mode is read-only by design, so this is safe to run even on main. When the plan looks right, approve it and Claude switches to execution.
Trace the Dependency Graph First
Section titled “Trace the Dependency Graph First”Before a rename or schema change, make Claude surface everything that depends on the thing you’re about to move. This is faster and more reliable than grep because it follows imports and types, not just text.
Use the returned checklist as the contract for the edit pass. If Claude later edits a file that wasn’t on the list, that’s your signal to pause and re-check the plan.
Safe Renames Across the Codebase
Section titled “Safe Renames Across the Codebase”A rename looks trivial until it’s a public field that external clients depend on. The pattern that survives production is additive-then-deprecate, not rip-and-replace.
-
Add the new name alongside the old. Keep both working so nothing breaks on deploy.
-
Migrate internal callers to the new name while the API still accepts the old one.
-
Deprecate the old name with a warning so you can see remaining usage.
-
Remove the old name once telemetry confirms no active callers.
For typed languages, lean on Claude’s ability to propagate types instead of chasing compiler errors by hand:
Cross-Cutting Refactors
Section titled “Cross-Cutting Refactors”When logic is duplicated across controllers or services, ask Claude to consolidate it while preserving the existing public interfaces — the consolidation should be invisible to callers.
Extract the validation logic duplicated in UserController, OrderController, andProductController into a single ValidationService. Keep each controller's existingmethod signatures unchanged. Add unit tests for the extracted service.Standardize error handling across the API: introduce a small set of typed errorclasses, route them through one error-handling middleware, and replace ad-hoctry/catch + res.status(...) blocks with throws. Keep response shapes identical soclients don't break. Update affected tests.Add a request-id that's generated per request and included in every structured logline for that request. Wire it through the logger and the error handler. Don't logPII. Show me the middleware and one updated handler before doing the rest.When a refactor touches an MCP-connected system — for example renaming a column that exists in your actual database — connecting the Postgres MCP server lets Claude read the live schema instead of guessing from migrations. See the refactoring patterns lesson for that workflow.
Work One Layer at a Time
Section titled “Work One Layer at a Time”For large changes, drive Claude through the stack in order rather than asking for everything at once. Narrow, sequential prompts keep context focused and make each diff reviewable.
1. "List every file that needs to change for user roles, grouped by layer."2. "Implement the database migration and model changes only."3. "Now the role-check middleware and the protected routes."4. "Now the role-management UI."5. "Now update and run the tests."Between unrelated phases, run /clear to drop stale context, or /compact Focus on the role-check seam and the files we've already changed to summarize while keeping what matters. Use /context to see what’s actually consuming the window, and /cost to watch spend. These are real interactive slash commands — run them inside the claude REPL, not as terminal flags.
Running Independent Tasks in Parallel
Section titled “Running Independent Tasks in Parallel”If you have several genuinely independent streams of work — a new auth system, a payments rewrite, an analytics pass — run each in its own git worktree so they get isolated working directories and branches. This is the documented way to parallelize, and it keeps each task’s context clean.
# One worktree (and branch) per stream of workgit worktree add ../feature-auth feature/authenticationgit worktree add ../feature-payments feature/paymentsgit worktree add ../feature-analytics feature/analytics
# Launch Claude Code in each worktree (separate terminals or tmux panes)tmux new-session -d -s auth 'cd ../feature-auth && claude'tmux new-session -d -s payments 'cd ../feature-payments && claude'tmux new-session -d -s analytics 'cd ../feature-analytics && claude'Each session is its own conversation against its own checkout, so the edits never collide. When you’re done with a tree, git worktree remove ../feature-auth.
Choose the right parallelism mechanism:
| Mechanism | Best for |
|---|---|
Git worktrees + one claude per tree | Independent tasks on separate branches that must not touch each other’s files. |
| Subagents | Specialized helpers inside one session (clean sub-context, fast handoffs) — launch with the --agents flag or define them in .claude/agents/. |
| Agent teams | Multiple agents that coordinate and message each other; set --teammate-mode and enable with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. |
If you instead need Claude to read across several directories in a single session (a monorepo app plus a shared lib), don’t use worktrees — add the directories with --add-dir:
claude --add-dir ../apps ../lib "Update the shared logger and every app that imports it"Coordinating Changes Across Repositories
Section titled “Coordinating Changes Across Repositories”Claude works one repository at a time, so cross-repo changes are sequential. Drive the producer first, then each consumer, and pin the contract in each repo’s CLAUDE.md so future sessions know what changed.
cd api-serviceclaude "Update the /users endpoint to return clientId instead of customerId,but keep accepting customerId on input for one release."
cd ../frontend-appclaude "The /users API now returns clientId (customerId is deprecated).Update all calls and data handling to read clientId."
cd ../mobile-appclaude "Update to read clientId from the /users API, keeping a fallback tocustomerId so older app builds keep working."cd shared-utilsclaude "Add validateEmail and validatePhone helpers, exported from the package root."
for service in user-service order-service notification-service; do cd "../$service" claude "Bump shared-utils to the version that adds validateEmail/validatePhone and replace local validation with those helpers."doneRecord the migration in each repo so the next session has the context:
<!-- in each repo's CLAUDE.md -->## Recent migrations- clientId replaces customerId in /users responses; customerId still accepted on input until v3.When This Breaks
Section titled “When This Breaks”Multi-file edits fail in predictable ways. Here’s how to catch and recover from each.
When an edit pass goes wrong, git is your undo:
git status # see everything that changedgit diff # review before trusting anythinggit checkout -- path/to/file.ts # revert a single filegit reset --hard HEAD # nuke all uncommitted changes and start overFor a partial recovery — keep the good, drop the broken — describe it precisely:
Commit in logical phases as you go (after the migration, after the middleware, after the UI). Small, frequent commits turn “the whole change is broken” into “the last commit is broken.”
What’s Next
Section titled “What’s Next”- Refactoring Patterns — deeper rename, extract, and restructure recipes
- Debugging Workflows — when a multi-file change introduces a bug
- Custom Subagents — specialized helpers for large changes inside one session
- Cost Control — keep large multi-file sessions cheap