Framework Migration Workflow in Cursor
Your React application uses class components, Redux with connect(), React Router v5, and a custom Webpack build. The team wants to move to functional components with hooks, Zustand for state, React Router v7, and Vite. There are 180 components, 45 Redux-connected containers, and 30 route definitions. A full rewrite would take months and halt feature development. A gradual migration lets you keep shipping features while modernizing — but you need a systematic approach to avoid ending up with a codebase that is half old patterns and half new patterns forever.
Framework migrations are one of Cursor’s strongest use cases. The transformations are mechanical (converting class syntax to function syntax, replacing one API with another), the patterns are well-documented, and the volume is high enough that AI assistance pays for itself many times over. The challenge is not the individual transformation — it is orchestrating 180 of them without breaking anything.
What You’ll Walk Away With
Section titled “What You’ll Walk Away With”- A planning workflow that maps your migration scope before changing any code
- Prompts for automated, file-by-file transformation with validation
- A strangler fig strategy that lets you migrate incrementally without a big bang
- Techniques for handling the hardest migrations (state management, routing, build tools)
- Project rules that prevent mixing old and new patterns in new code
Planning the Migration
Section titled “Planning the Migration”Every migration starts with an inventory. You need to know exactly what you are migrating, how many files are affected, and which transformations are needed. Plan mode is built for this.
Plan mode will scan your codebase and produce a structured breakdown. A typical output might look like:
- 95 simple class components (no state, no lifecycle) — auto-migratable
- 50 medium components (state and componentDidMount) — semi-automatic
- 35 complex components (multiple lifecycle methods, shouldComponentUpdate) — needs review
- 45 Redux-connected components — depends on Zustand migration
- 30 route definitions — batch migration after components are done
This inventory becomes your migration roadmap.
The Strangler Fig Pattern
Section titled “The Strangler Fig Pattern”The safest migration strategy is the strangler fig: new code uses new patterns, old code gets migrated incrementally, and both coexist until the migration is complete. Cursor project rules enforce this boundary.
# Migration Rules (Active)
## New Code- All new components MUST be functional components with hooks- All new state management MUST use Zustand stores- All new routes MUST use React Router v7 data loader pattern- No new code may use: class components, Redux connect(), React Router v5 Switch
## Coexistence- Old class components can import new hooks via wrapper functions- Old Redux-connected components can read from Zustand stores via a bridge- Both routing systems run simultaneously via a compatibility layer
## Migration Status- Components: 45/180 migrated (25%)- Redux stores: 2/8 migrated (25%)- Routes: 0/30 migrated (0%)Update the migration status in this rule file as you progress. Agent reads it on every interaction, so it always knows the current state of the migration.
Migrating Components
Section titled “Migrating Components”Simple Components (Stateless)
Section titled “Simple Components (Stateless)”The easiest migration: class components with no state and no lifecycle methods.
For batch migration, you can process multiple files at once:
Migrate these 5 stateless class components to functional components.Apply the same transformation to each:
@src/components/Badge.tsx@src/components/Card.tsx@src/components/Divider.tsx@src/components/Icon.tsx@src/components/Label.tsx
For each file: convert class to function, destructure props, preserve behavior exactly.After migration, run "npm run type-check" to verify TypeScript compilation.Medium Components (Lifecycle Methods)
Section titled “Medium Components (Lifecycle Methods)”Components with state and lifecycle methods require more careful transformation:
Complex Components (HOCs, Render Props)
Section titled “Complex Components (HOCs, Render Props)”Complex components need individual attention:
Migrating State Management
Section titled “Migrating State Management”The Redux-to-Zustand migration is the highest-risk part because state management touches every connected component. Migrate one store at a time.
Migrating Routing
Section titled “Migrating Routing”Router migration is best done as a batch because routes are interdependent:
Build Tool Migration
Section titled “Build Tool Migration”Webpack to Vite is typically done in one session because it is configuration-only:
When This Breaks
Section titled “When This Breaks”Agent migrates code incorrectly and tests pass because tests are also outdated. This is the most dangerous migration bug. Before migrating a component, verify that its existing tests actually exercise the behavior you care about. Ask Agent: “Before migrating this component, review its test file. Do the tests cover the key behaviors, or are they just checking that it renders?”
The migration bridge causes performance issues. Syncing state between Redux and Zustand on every change creates unnecessary re-renders. Keep the bridge simple (one-directional sync) and remove it as soon as all consumers of that store are migrated.
Half-migrated code confuses Agent. When your codebase has both old and new patterns, Agent sometimes generates code using the old pattern because it sees more examples of it. The migration rules file at the top of this article prevents this — but only if it is set to “Always Apply.”
The migration stalls at 80%. The last 20% of components are always the hardest because they are the most complex. Do not leave them. Schedule dedicated migration sprints and use Cursor’s Plan mode to break each complex component into smaller, manageable steps.
Rollback is needed after partial migration. Keep the old code paths available (commented out or behind feature flags) until the migration is verified in production. Cursor’s checkpoints help with per-session rollbacks, but for multi-day migrations, use Git branches.