Migrating an Angular application
craft-migrate runs the Craft NG codemods in their required order:
- Angular signals and primitive migration points
- Angular services and their consumers
- Angular route collections and type-safe DI checks
- Legacy
component(...)factories tocraftComponent(name, ...)
The migration is intentionally conservative. Deterministic transformations are written automatically; code requiring a business or lifecycle decision is reported as a manual diagnostic.
Install the migration tool
npm install @craft-ng/core
npm install --save-dev @craft-ng/dev-tools@betaThe migration binaries are available starting with 0.5.1-beta.0 and are currently published on the beta tag. The latest version and older beta versions do not include craft-migrate. If the package was installed before that release, update it and verify the resolved version:
npm install --save-dev @craft-ng/dev-tools@beta
npm ls @craft-ng/dev-toolsCommit or stash the current application changes before writing a migration. The codemod does not revert unrelated local changes.
Preview the migration
Run the command from the application workspace:
npx craft-migrate \
--project tsconfig.app.json \
--root src \
--dry-runFor an Angular CLI workspace, the project file is commonly under the application directory:
npx craft-migrate \
--project projects/my-app/tsconfig.app.json \
--root projects/my-app/src \
--dry-runUse a JSON report when the diagnostics need to be reviewed or archived:
npx craft-migrate \
--project tsconfig.app.json \
--root src \
--dry-run \
--json migration-report.jsonApply the migration
npx craft-migrate \
--project tsconfig.app.json \
--root src \
--write--write runs ESLint fixes on files touched by the primitive and service migrations. Use --no-eslint only when linting is managed separately.
The specialized commands remain available when a migration must be applied or debugged one stage at a time:
npx craft-migrate-primitives --project tsconfig.app.json --root src --write
npx craft-migrate-services --project tsconfig.app.json --root src --write
npx craft-migrate-routes --project tsconfig.app.json --root src --write
npx craft-migrate-components --project tsconfig.app.json --root src --writeFor a pasted HTML/Web Component snippet, use the standalone template converter:
printf '<section><h2>Hello</h2></section>' | npx craft-migrate-templateThe generated callback can be pasted as the fourth argument of craftComponent(...). The interactive template converter uses the same converter directly in the documentation.
Work remaining after the codemod
Search the generated report and source code for migration diagnostics. In particular, complete the following work before considering the migration done:
- Rewrite Angular Signal Forms as
state(name, ..., insertForm(...)). - Consume every primitive invocation (
state,query,mutation,asyncProcess,queryParams):yield*inside a generator factory,craftUse(...)in a component field. Thecraft-ng/require-primitive-generator-unwrapESLint rule reports and autofixes the remaining bare calls, andmigrate-primitive-generators --paths <glob>migrates whole directories. - Map synchronous validators to
cRequired,cMaxLength, and the other Craft validators. - Replace asynchronous form validation with
queryandcAsyncValidate. - Replace form submission workflows with
mutationandinsertFormSubmit. - Resolve every
CRAFT_IMPLEMENTATION_REQUIREDcompanion service. - Review generated service scopes and move
provideX(...)close to the route or feature that owns the instance. - Replace remaining direct Angular
inject(...)calls withtoCraftService(...)adapters, then consume their generatedX()helpers withyield*. The formerinjectXandXToYieldhelpers are no longer part of the API. - Resolve imperative workflow diagnostics instead of only removing their comments.
- Migrate guards, dynamic redirects, nested route collections, inherited route providers, and other route diagnostics that could not be inferred safely.
- Confirm
componentDeps, route provider names, and file-level DI checks are complete. - Review HTTP mutations and subscriptions whose callback or lifecycle semantics could not be moved automatically.
Verify the result
First make remaining migration work fail CI:
npx craft-migrate \
--project tsconfig.app.json \
--root src \
--check \
--fail-on-manualThen run the normal project verification:
npx eslint "src/**/*.ts"
npx tsc --noEmit -p tsconfig.app.json
npx ng test
npx ng buildUse the workspace-specific lint, test and build commands when they differ. Finally, exercise forms, navigation, pending/error UI, and write operations in the browser: those lifecycle behaviours cannot be fully established by a structural codemod.