🔄Code Migration & Refactoring
Use Claude to migrate codebases, upgrade frameworks, and refactor at scale
Code Migration & Refactoring
Large-scale code migration is one of the most tedious and error-prone tasks in software engineering. Whether you are upgrading a framework, switching languages, or modernizing a legacy codebase, Claude Code can dramatically accelerate the process while reducing the risk of regressions.
This lesson covers battle-tested strategies for using Claude Code to perform migrations that would normally take weeks or months of manual effort.
Why Migrations Are Hard
Migrations involve far more than search-and-replace. They require:
- Semantic understanding of the old and new patterns
- Context awareness across files that depend on each other
- Incremental validation to catch breakages early
- Rollback safety in case something goes wrong
Claude Code excels at all of these because it can hold your entire project context in memory, understand the intent behind code, and apply consistent transformations across hundreds of files.
Migration Strategy Overview
Every successful migration follows a predictable lifecycle:
Phase 1: Audit → Understand what needs to change
Phase 2: Plan → Define the transformation rules
Phase 3: Transform → Apply changes file-by-file or in batches
Phase 4: Validate → Run tests, linters, and type checks
Phase 5: Stabilize → Fix edge cases and regressions
Phase 6: Document → Record what changed and why
Let us walk through each phase with Claude Code.
Phase 1: Auditing the Codebase
Before changing anything, you need a clear picture of the current state.
Scanning for patterns
# Ask Claude Code to audit your codebase
claude "Scan this project and list every file that uses React class components.
Group them by directory and note which ones have state, lifecycle methods,
or refs. Output a markdown table."Generating a migration manifest
claude "Create a migration-manifest.json that lists every file needing migration
from Express to Fastify. For each file include: path, complexity (low/medium/high),
dependencies on Express-specific APIs, and estimated effort."This gives you a structured plan you can track with your team.
Phase 2: Defining Transformation Rules
Claude Code works best when you give it explicit rules to follow.
Creating a migration guide
claude "Create a MIGRATION_RULES.md file that defines how to convert
Express middleware to Fastify plugins. Include:
1. Route handler signature changes
2. Middleware → plugin/hook equivalents
3. Error handling differences
4. Request/response API mappings
Use concrete before/after code examples for each rule."Setting up CLAUDE.md for consistency
Add migration-specific instructions to your project's CLAUDE.md so every Claude Code session follows the same rules:
# Migration Rules
- When converting Express routes to Fastify, use the schema-based validation
- Replace req.body with request.body and use Fastify's built-in parsing
- Convert app.use() middleware to Fastify register() plugins
- Preserve all existing test assertions, only change the setup codeFramework Upgrades
React Class Components to Hooks
This is one of the most common migration scenarios. Claude Code handles it well because the transformation is pattern-based but requires semantic understanding.
claude "Convert src/components/UserProfile.jsx from a class component to a
functional component with hooks. Requirements:
- Convert this.state to useState
- Convert componentDidMount to useEffect with empty deps
- Convert componentDidUpdate to useEffect with appropriate deps
- Convert componentWillUnmount to useEffect cleanup
- Convert this.handleX methods to const handlers
- Preserve all prop types
- Keep the same export signature"Handling complex class patterns
Some class components have patterns that do not map one-to-one to hooks:
claude "This component uses getDerivedStateFromProps and componentDidCatch.
Convert to hooks using:
- useMemo or direct computation for derived state
- An ErrorBoundary wrapper component (keep as class) for componentDidCatch
Explain any patterns that cannot be directly converted to hooks."Express to Fastify
claude "Migrate src/routes/auth.js from Express to Fastify.
Follow these rules:
- Convert router.get/post to fastify.get/post
- Replace express.Router() with a Fastify plugin function
- Convert middleware chains to Fastify preHandler hooks
- Add JSON Schema validation for request bodies
- Update error handling to use Fastify's reply.code().send()
- Keep the same business logic untouched"JavaScript to TypeScript
This is a migration where Claude Code truly shines because it can infer types from runtime usage patterns.
claude "Convert src/utils/api-client.js to TypeScript. Requirements:
- Infer types from usage patterns across the codebase
- Create interfaces for all function parameters and return types
- Use strict mode (no 'any' types unless absolutely necessary)
- Add generics where the function handles multiple types
- Rename the file to .ts and update all imports across the project"Language Migrations
Python 2 to Python 3
claude "Migrate src/legacy/data_processor.py from Python 2 to Python 3.
Handle these specific changes:
- print statements to print() functions
- unicode/str to str/bytes
- dict.iteritems() to dict.items()
- xrange to range
- Update exception syntax
- Fix integer division behavior
- Update imports (ConfigParser, urllib, etc.)
Preserve all existing functionality and add type hints."CommonJS to ES Modules
claude "Convert this project from CommonJS to ES Modules.
For each file:
- Change require() to import statements
- Change module.exports to export/export default
- Update dynamic requires to dynamic import()
- Add .js extensions to relative imports
- Update package.json to add type: module
List any circular dependencies that need manual resolution."API Version Upgrades
When an API you depend on releases a breaking version, Claude Code can handle the upgrade across your entire codebase.
claude "Upgrade all Stripe API calls from v2022-11-15 to v2024-04-10.
Read the Stripe changelog and apply these changes:
- Update the stripe package to the latest version
- Fix all deprecated API calls
- Update webhook event type names
- Adjust error handling for new error types
- Update TypeScript types if using @types/stripe
Show me a diff summary before applying changes."Handling breaking changes systematically
claude "I need to upgrade from Next.js 13 to Next.js 15.
1. First, scan the project and list all breaking changes that affect us
2. Create a prioritized migration plan
3. Start with the lowest-risk changes (config files, imports)
4. Then handle the app router migration
5. Finally update any changed APIs
Do NOT change test files yet - I want to validate each step."Database Migration Generation
Claude Code can generate database migrations based on schema changes.
claude "Compare the current Prisma schema with the production database schema
in schema.backup.prisma. Generate a migration that:
- Adds the new fields without dropping existing data
- Handles column renames with data preservation
- Creates indexes for the new query patterns
- Includes a rollback migration
- Is safe for zero-downtime deployment"ORM migration between frameworks
claude "Migrate our data access layer from Sequelize to Prisma.
For each model:
- Create the equivalent Prisma schema definition
- Convert query methods to Prisma Client calls
- Handle associations/relations mapping
- Update transaction patterns
- Preserve all existing query behavior
Generate a prisma/schema.prisma and update all repository files."Batch File Processing with Claude Code
For large migrations, processing files one at a time is too slow. Use Claude Code's ability to work across multiple files.
Processing entire directories
claude "Convert ALL .jsx files in src/components/ to TypeScript (.tsx).
For each file:
1. Infer prop types from usage and create interfaces
2. Add proper return types to components
3. Type all useState, useRef, and useContext calls
4. Type event handlers with React event types
5. Rename the file from .jsx to .tsx
Process them in dependency order (leaf components first)."Using shell scripts with Claude Code
For very large codebases, combine shell scripting with Claude Code:
# Process files in batches
for file in src/legacy/*.js; do
claude "Convert $file from JavaScript to TypeScript.
Follow the rules in MIGRATION_RULES.md.
Run tsc --noEmit after conversion to verify types." --no-interactive
doneTracking migration progress
claude "Check our migration progress:
- Count files already migrated to TypeScript (.ts/.tsx)
- Count files still in JavaScript (.js/.jsx)
- List the remaining files sorted by import count (most imported first)
- Calculate the percentage complete
Update migration-tracker.md with the current status."Testing Migration Results
Migration without testing is just introducing bugs with extra steps.
Generating comparison tests
claude "For each migrated component in src/components/:
1. Check if a test file exists - if not, create one
2. Verify the test covers the same behavior as before migration
3. Add snapshot tests to catch unintended rendering changes
4. Run the test suite and report any failures
5. For failures, determine if the test or the migration is wrong"Type checking as validation
claude "Run tsc --noEmit on the entire project and fix all type errors.
For each error:
- If it is a missing type, add the correct type
- If it is an incompatible type, check the migration logic
- If it is a third-party type issue, add a @ts-expect-error with explanation
Do NOT use 'any' to suppress errors."Integration testing after migration
claude "Create an integration test that verifies our Express-to-Fastify migration
did not break any API contracts. The test should:
- Hit every endpoint with the same requests as our old Express tests
- Compare response status codes, headers, and body shapes
- Verify error responses match the old format
- Check that middleware behavior (auth, rate limiting) is preserved"Rollback Strategies
Every migration needs an escape hatch.
Git-based rollback
# Create a migration branch with clear checkpoints
claude "Set up our migration with git checkpoints:
1. Create a branch 'migration/express-to-fastify'
2. After each file migration, create a commit with a descriptive message
3. After each batch, create a tag like 'migration-checkpoint-1'
4. Document the rollback command for each checkpoint in ROLLBACK.md"Feature flags for gradual migration
claude "Set up feature flags so we can run both Express and Fastify in parallel:
- Create a MIGRATION_FLAGS.ts config file
- Add a flag for each migrated route group
- Implement a proxy that routes to old or new handler based on the flag
- Add logging to compare response times between old and new"Dual-running for safety
claude "Implement a shadow-mode migration validator:
- For each request, run both the Express and Fastify handler
- Compare the responses (status, body, headers)
- Log any discrepancies without affecting the user
- Send metrics to our monitoring dashboard
This lets us validate the migration with real production traffic."Practical Example: Migrating a JavaScript Project to TypeScript
Let us walk through a complete, real-world migration step by step.
Step 1: Initialize TypeScript
claude "Initialize TypeScript in this project:
- Install typescript and necessary @types packages
- Create a tsconfig.json with strict mode enabled
- Configure paths, baseUrl, and module resolution
- Set allowJs: true so we can migrate incrementally
- Add a build script to package.json"Step 2: Start with utility files
claude "Start the TS migration with src/utils/ (lowest dependency count):
- Convert each .js file to .ts
- Add explicit types to all exported functions
- Create shared type definitions in src/types/
- Run tsc --noEmit to verify
- Fix any errors before moving to the next file"Step 3: Migrate the data layer
claude "Migrate src/models/ and src/repositories/ to TypeScript:
- Create interfaces for all database entities
- Type all query functions with proper generics
- Add return type annotations to all repository methods
- Ensure nullable fields are properly typed with | null
- Validate with tsc --noEmit"Step 4: Migrate the API layer
claude "Migrate src/routes/ and src/middleware/ to TypeScript:
- Type all request handlers with Express.Request and Express.Response
- Create interfaces for request bodies and query params
- Type middleware functions properly
- Add error types for custom error classes
- Verify all routes still work with npm test"Step 5: Migrate components (if applicable)
claude "Migrate all React components in src/components/ to TypeScript:
- Create prop interfaces for each component
- Type all hooks usage (useState<Type>, useRef<Type>)
- Type context values and providers
- Convert .jsx to .tsx
- Run the test suite after each batch"Step 6: Remove JavaScript allowance
claude "Finalize the TypeScript migration:
- Set allowJs: false in tsconfig.json
- Remove any remaining .js files (should be none)
- Enable strict: true and fix all new errors
- Update CI/CD pipeline to run tsc --noEmit
- Update the README with new development instructions
- Create a migration completion report"Best Practices for Large-Scale Migration
-
Migrate incrementally - Never try to migrate everything at once. Use allowJs or equivalent flags to let old and new code coexist.
-
Test after every change - Run your test suite after each file or batch. If tests break, fix them before moving on.
-
Keep the migration atomic per feature - Migrate a complete feature (model + routes + tests) rather than all models, then all routes.
-
Use CLAUDE.md rules - Document your migration patterns so Claude Code applies them consistently across every session.
-
Preserve git history - Use small, descriptive commits so you can trace what changed and roll back specific transformations.
-
Monitor after deployment - Even after tests pass, watch error rates, performance metrics, and logs closely after deploying migrated code.
-
Document decisions - Record why you chose certain type annotations, pattern replacements, or architectural decisions during the migration.
Summary
Code migration with Claude Code follows a disciplined process:
| Phase | Claude Code Helps With |
|---|---|
| Audit | Scanning patterns, generating manifests |
| Plan | Creating transformation rules, writing CLAUDE.md |
| Transform | Applying changes across files with semantic understanding |
| Validate | Running tests, fixing type errors, catching regressions |
| Stabilize | Edge case handling, integration testing |
| Document | Migration reports, updated documentation |
By combining Claude Code's understanding of code semantics with a structured migration process, you can tackle migrations that would otherwise be too risky or time-consuming to attempt.