DEV Community

brian austin
brian austin

Posted on

Claude Code multi-file refactor: how to restructure a codebase without breaking everything

Claude Code multi-file refactor: how to restructure a codebase without breaking everything

Refactoring a large codebase is where most developers hesitate to use AI. Too many files. Too many dependencies. Too easy to break something in file C when you're editing file A.

Here's the systematic approach that actually works with Claude Code.

The problem with naive refactoring

Asking Claude Code "refactor this codebase" is asking for trouble. You'll get:

  • Changes that break imports in files Claude didn't read
  • Renamed functions that still have the old name in 6 other places
  • New patterns introduced inconsistently across files

The solution is structured multi-file context management.

Step 1: Map before you move

Before touching a single file, ask Claude Code to build a dependency map:

> Read the src/ directory structure. List every file, what it exports, and what it imports. Don't change anything yet.
Enter fullscreen mode Exit fullscreen mode

Claude will read each file and build a mental model. This is your safety net.

Save it:

> Write that dependency map to REFACTOR_PLAN.md. Include: file path, exports, imports, and any circular dependencies.
Enter fullscreen mode Exit fullscreen mode

Step 2: Define the target architecture

Now describe what you want the end state to look like:

> I want to reorganize this into:
- /src/models/ — pure data types, no side effects
- /src/services/ — business logic, one file per domain
- /src/routes/ — HTTP handlers only, thin wrappers
- /src/utils/ — shared helpers

Update REFACTOR_PLAN.md with the target location for each current file.
Enter fullscreen mode Exit fullscreen mode

Claude will reason through the mapping and flag conflicts before you've changed anything.

Step 3: Refactor in layers, not all at once

The key insight: refactor one layer at a time, test between each layer.

> Start with models only. Move the types from src/database.js to src/models/user.js and src/models/post.js. Update all imports. Run tests after each file move.
Enter fullscreen mode Exit fullscreen mode

Never ask Claude to refactor multiple layers simultaneously. The blast radius is too large.

Step 4: The import update pattern

The most common refactor failure is missed imports. Use this pattern:

> After moving [filename], grep the entire codebase for any import of [old-path] and update each one. Show me every file you changed.
Enter fullscreen mode Exit fullscreen mode

This explicit grep-then-update command catches the stragglers that break at runtime.

Step 5: Run tests after every file move

Don't batch up 10 moves and test at the end. Test incrementally:

> Move src/auth.js to src/services/auth.js. Update imports. Run `npm test`. If tests fail, stop and show me the errors before continuing.
Enter fullscreen mode Exit fullscreen mode

The "stop and show me" instruction is critical. Without it, Claude may attempt to fix failures silently and create cascading problems.

Handling circular dependencies

Claude Code is excellent at identifying and breaking circular dependencies:

> I see that services/user.js imports from services/post.js and post.js imports from user.js. Propose 3 ways to break this circular dependency without changing the external API.
Enter fullscreen mode Exit fullscreen mode

Claude will reason through the options. Pick one, then:

> Implement option 2. Create the shared types in models/shared.js first, then update both service files.
Enter fullscreen mode Exit fullscreen mode

The CLAUDE.md checkpoint pattern

For multi-session refactors, maintain a checkpoint file:

# REFACTOR STATUS

## Completed
- [x] models/user.js — moved, imports updated, tests passing
- [x] models/post.js — moved, imports updated, tests passing

## In Progress
- [ ] services/auth.js — moved, imports NOT YET updated

## Blocked
- services/billing.js — circular dep with services/user.js, needs design decision

## Next Session
Start with: resolve billing.js circular dependency (see REFACTOR_PLAN.md line 47)
Enter fullscreen mode Exit fullscreen mode

At the start of each session:

> Read REFACTOR_PLAN.md and REFACTOR_STATUS.md. Continue from where we left off.
Enter fullscreen mode Exit fullscreen mode

Claude picks up exactly where you stopped.

When to use --dangerously-skip-permissions

For large refactors, you'll hit permission prompts constantly. In a sandboxed environment:

claude --dangerously-skip-permissions
Enter fullscreen mode Exit fullscreen mode

This lets Claude move files, create directories, and update imports without interrupting you for every operation. Only use this in repos where you have clean git state (so you can roll back).

Real example: extracting a monolith

Here's a sequence that moved a 3,000-line server.js into a proper service architecture:

> server.js is 3,000 lines. Read it. Identify all logical domains (auth, payments, users, notifications). List them.

> Create the directory structure for these domains under src/services/. Empty files only.

> Extract the auth functions (lines ~200-450) into services/auth.js. Update server.js to import from there. Run tests.

> Extract the payment functions. Run tests.

[repeat for each domain]

> server.js should now be thin route handlers only. Verify it's under 300 lines. Show me what's left.
Enter fullscreen mode Exit fullscreen mode

Total time: 45 minutes. Zero test failures at the end.

The rate limit problem at scale

Large refactors are where Claude Code's rate limits hit hardest. You're reading many files, writing many files, running tests repeatedly. A single large refactor session can hit the limit mid-operation — exactly when you don't want to stop.

The fix developers use: set ANTHROPIC_BASE_URL to a proxy that removes per-session limits.

export ANTHROPIC_BASE_URL=https://simplylouie.com
Enter fullscreen mode Exit fullscreen mode

SimplyLouie is ✌️$2/month and removes the rate limit interruptions during long refactor sessions. 7-day free trial, no charges until day 8.

Summary: the refactor protocol

  1. Map first — dependency map before any changes
  2. Plan in CLAUDE.md — write target architecture, let Claude verify feasibility
  3. Layer by layer — models first, then services, then routes
  4. Test after every file move — not after 10 moves
  5. Explicit import grep — always ask Claude to grep for old paths after moves
  6. Checkpoint file — for multi-session refactors, maintain REFACTOR_STATUS.md
  7. Clean git state — commit before refactor, commit after each layer

The difference between a successful large-scale refactor and a week of debugging is almost always process. Claude Code is capable of handling it — it just needs a structured protocol to work from.

Top comments (0)