How to use Claude Code for large-scale refactoring: rename symbols across a codebase, extract modules, migrate frameworks, and restructure code safely.
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 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
# 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
# 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."
# 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 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)"
# 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"
# 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.