Refactoring with Claude Code

How to use Claude Code for large-scale refactoring: rename symbols across a codebase, extract modules, migrate frameworks, and restructure code safely.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Claude Code handles refactoring well because it can read the full codebase context — not just the file you're editing. Here are the patterns for safe, effective large-scale changes.

Rename across codebase

# Rename a function everywhere it's used:
"Rename the function get_user_by_id to fetch_user in all Python files.
Update the definition in src/db/users.py and all callers."

# Claude:
# 1. Greps for get_user_by_id across all .py files
# 2. Lists every file that uses it
# 3. Edits each file: definition + all call sites
# 4. Reports what was changed

# Verify afterward:
grep -r 'get_user_by_id' .   # should be empty

Extract a module

# Split a large file into smaller modules:
"src/utils.py has grown to 1200 lines. Split it:
- auth-related functions → src/utils/auth.py
- date/time functions → src/utils/dates.py
- string formatting → src/utils/formatting.py

Keep backward compatibility: src/utils.py should re-export everything
from the new modules so existing imports still work."

# Claude:
# 1. Reads src/utils.py
# 2. Categorizes each function
# 3. Creates the three new files
# 4. Updates src/utils.py to re-export all symbols
# 5. Verifies no import cycles

Library migration

# Migrate from requests to httpx (async-compatible):
"Migrate all HTTP calls in src/ from the requests library to httpx.

Key differences:
- requests.get() → httpx.get() (sync) or await client.get() (async)
- response.json() stays the same
- Timeouts: requests.get(url, timeout=5) → httpx.get(url, timeout=5)
- Session: requests.Session() → httpx.Client() (sync) or httpx.AsyncClient() (async)

Our code is async (FastAPI), so use AsyncClient everywhere.
Replace sync calls with async equivalents and add 'await' where needed."

Framework migration (e.g., Flask → FastAPI)

# Phased migration approach:
"I'm migrating from Flask to FastAPI. Let's do it one router at a time.

Start with src/routes/users.py only.

Flask pattern we use:
@app.route('/users', methods=['GET'])
def get_users():
    return jsonify(users_list)

FastAPI equivalent:
@router.get('/users')
def get_users() -> list[UserSchema]:
    return users_list

Convert src/routes/users.py from Flask to FastAPI syntax.
Use Pydantic models (already in src/schemas/) for request/response types."

Add type annotations to existing code

# Add type hints to a file progressively:
"Add Python type annotations to all functions in src/services/payments.py.

Rules:
- Use types from the standard library (list, dict, Optional, Union)
- Import from typing for Python 3.9 compatibility
- For SQLAlchemy models, use the model class type (e.g., User, not Any)
- If a return type is unclear, use Any with a comment explaining why
- Don't add annotations to private helper functions (_prefixed)"

Safe refactor workflow

# Step 1: Create a branch
git checkout -b refactor/extract-payment-module

# Step 2: Scope the refactor explicitly
"Only touch files in src/payments/ and tests/test_payments/.
Do not modify any other files."

# Step 3: Refactor in phases
"Phase 1: Extract PaymentProcessor class from src/payments/process.py
into src/payments/processor.py. No other changes yet."

# Step 4: Run tests after each phase
pytest tests/test_payments/ -x -q

# Step 5: Continue phases
"Phase 2: Update src/payments/process.py to import from processor.py"

# Step 6: Full test suite
pytest

# Step 7: Review
/review    # or: git diff main..HEAD | claude --print "Review this refactor"

Remove dead code

# Find and remove unused code:
"Find all functions in src/ that are defined but never called anywhere
in the codebase (including tests). List them first before removing anything."

# Claude uses Grep to find definitions, then searches for usages of each.
# Lists candidates. You review. Then:
"Remove the functions from the dead code list: [list from above]"

For reviewing refactors before committing, see Claude Code code review workflow. For managing git branches during large refactors, see Claude Code git workflow.

Frequently asked questions

Can Claude Code refactor code across multiple files?
Yes. Claude Code reads multiple files, understands cross-file dependencies, and makes coordinated edits across your whole codebase. For large refactors, break the work into phases (e.g., first rename, then update callers, then update tests).
How do I rename a function used across 50 files?
Ask Claude Code: 'Rename function old_name to new_name across the entire codebase'. Claude uses Grep to find all usages, then edits each file. Verify with grep -r 'old_name' . afterward.
Can Claude Code migrate from one library to another (e.g., requests to httpx)?
Yes. Give Claude the migration goal and the key API differences. Claude reads your code, finds all usages of the old library, and rewrites them using the new API. Works best one file at a time for large codebases.
How do I safely refactor a large codebase without breaking things?
Use git branches, run tests after each refactor phase, and give Claude Code explicit scope boundaries ('only touch files in src/api/'). Ask Claude to add deprecation warnings before removing old APIs.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript