Migration
Migration guide
There are two kinds of migration. Upgrading the CLI moves a project the CLI created to a newer release. Adopting FSD moves an existing app that the CLI did not create into layers and slices. Pick the section that matches your project.
Upgrade a CLI-created project
- Commit or stash your work. Upgrades refuse a dirty worktree unless you pass
--allow-dirty. - Check the runtime. CLI 2.7.0 and later need Node.js 22.12.0 or later; Nuxt and SvelteKit need 22.22.2. See the requirements.
- Preview the plan, then apply it only when it has no conflicts.
node --version
npx create-fsd-architecture@latest upgrade --dry-run
npx create-fsd-architecture@latest upgrade --yesThe upgrade touches only files the CLI owns and rolls everything back if a step fails. Customized CLI-owned files are reported as conflicts for you to resolve by hand. The safe upgrades guide explains the plan, the ownership manifest, and the CI exit codes.
Notes by version
| From | What to do |
|---|---|
| 2.6.x → 2.7.x | Breaking: Node.js 20 is no longer supported. Upgrade Node.js first, then run upgrade. The light-hooks-v1 migration updates unchanged Git hooks and reports customized ones. |
| Created before 2.6.1 | Upgrade with CLI 2.7.1 or later, which recognizes the older fsd-stack.ts rendering instead of reporting a conflict. |
| Created before 2.6.0 | No .fsd/manifest.json yet. The CLI adopts only files that match known released signatures (legacy mode); anything customized needs a manual merge. |
| 1.0.x | Legacy releases with no managed upgrade path. Treat the project as an existing app and follow the section below. |
Adopt FSD in an existing app
There is no command that rewrites an arbitrary app, and that is on purpose: every codebase splits differently. Migrate incrementally so the app builds and ships after every step.
- Baseline. Make sure lint, type checks, tests, and the build pass before you move anything.
- Create the structure. Structure-only generation adds layers and empty public APIs and never overwrites files.
- Move one concept at a time. Start with
shared, then entities, then features. Update imports to the slice'sindex.tsin the same commit. - Verify each batch. Re-run the baseline checks; revert the batch if they fail.
- Lock it in. Add Steiger and
check --architectureto CI so new code follows the rules.
npx create-fsd-architecture@latest -g shared --segments ui,lib,api,config --root src
npx create-fsd-architecture@latest -g entity product user --segments ui,model,api --root src
npx create-fsd-architecture@latest check --architectureWhere common folders go
| Typical folder | FSD location | How to decide |
|---|---|---|
| components/ (generic) | shared/ui | Buttons, inputs, and layout primitives with no business meaning. |
| components/ (business) | entities/<name>/ui or widgets/<name> | A ProductCard belongs to the product entity; a header with search is a widget. |
| pages/, routes/, views/ | pages/<name> | Keep the framework's route files; they import the page slice. |
| hooks/ | slice model or lib | Move each hook to the slice that owns its data; generic ones go to shared/lib. |
| services/, api/ | shared/api + entities/<name>/api | Keep one HTTP client in shared/api and entity requests next to their entity. |
| store/, redux/, stores/ | entities/<name>/model or features/<name>/model | Split global stores by the concept they describe. |
| utils/, helpers/ | shared/lib | Only truly generic helpers; business rules move into their slice. |
| constants/, config/ | shared/config | Environment and app-wide constants. |
| App, providers, global CSS | app | Providers, routing setup, and global styles. |
Let an agent do the moves
The AI Agent Skill runs this same plan with a coding agent: it inventories the app, proposes the mapping, moves code in validated batches, and restores a batch that fails. It is in preview, so review every batch.