author-migration

Author or scope a first-party Nx migration. Use whenever code removes, renames, or deprecates an option/flag/executor/generator-schema field, changes a default, or bumps a dependency, and someone asks whether existing workspaces need a migration so they don't break on `nx migrate`/upgrade. Covers writing the colocated update-VER/NAME.{ts,spec.ts,md} set, the migrations.json entry (version, requires, implementation, prompt, documentation) or packageJsonUpdates group, and the AI-agent prompt/runbook .md for prompt-only or hybrid (generator + prompt) migrations. Also covers porting an upstream framework's own migrations into Nx. Invoke BEFORE writing, fixing, or editing any migration, migration prompt/runbook, or packageJsonUpdates group, and before concluding a breaking change needs no migration at all.

Install
npx skills add 'https://github.com/nrwl/nx/tree/master/.claude/skills/author-migration'
Download bundle ↓
master · 646e806Scanned 2026-09-17

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md

Deprecated migration patterns

Two registries: patterns that exist only in git history (you will meet them when reading old migrations for reference, or in third-party plugins) and patterns still present in live code that must not be copied. When porting or referencing an old migration, rewrite it in the modern shape; never reproduce these.

Historical only (deleted from the repo)

PatternEraRecognition signatureModern replacement
Angular Devkit schematic Rulesv6-11import { Rule, chain } from '@angular-devkit/schematics'; updateJsonInTree, readJsonInTree, createOrUpdate, insert with Change objects; formatFiles() appended as a RuleDefault-exported async function (tree: Tree) using @nx/devkit
Top-level schematics section in migrations.jsonthrough 2023Entries under "schematics" instead of "generators"generators section (the schematics section routes through the Angular Devkit adapter)
Package bumps inside migration codev6-10addUpdateTask(...), RunSchematicTask chaining, updateJsonInTree('package.json', ...) bumpsDeclarative packageJsonUpdates; a .ts implementation only for conditional dep changes
workspace.json / angular.json editingv8-11updateWorkspaceInTree, getWorkspace / updateWorkspace, updateBuilderConfiggetProjects / updateProjectConfiguration; readNxJson / updateNxJson
@nrwl/* importsthrough ~v15from '@nrwl/workspace', from '@nrwl/devkit'; readWorkspaceConfiguration / updateWorkspaceConfiguration@nx/devkit
SchematicTestRunner specsv6-13SchematicTestRunner, UnitTestTree, runMigration('<name>', ...) against the collectioncreateTreeWithEmptyWorkspace + direct import of the default export. Note what was lost: the old helper loaded the migration BY NAME through migrations.json, so it validated the name-to-implementation wiring; direct-import specs do not, which is why the pre-PR checklist requires opening the file behind the manifest path
AI-instruction wrapper factoriespre mid-2026Factory that reads a files/<name>.md template and tree.writes tools/ai-migrations/MIGRATE_<THING>.md, returning string[]The prompt key pointing at a colocated .md; the runner writes the managed workspace copy under tools/ai-migrations/ itself
@nx/devkit/src/* deep importspre-23from '@nx/devkit/src/generators/...'@nx/devkit/internal

Still live, do not copy

PatternRecognition signatureRule
"cli": "nx" on entries"cli" key inside a generators entry (widespread in older entries)Dead key; new entries omit it
factory key"factory": "./dist/..."Tolerated alias; author implementation. Do not mass-rename existing entries
x-prompt on packageJsonUpdates"x-prompt": "Do you want to update..."Interactive-only and deprecated for removal in Nx v24; gate with requires instead
Slug-less or dotted entry keysupdate-22-2-0 (version, no action slug), 16.0.0-remove-nrwl-cli (dots instead of dashes); bare-version directories like 21-0-0/A key names its action (a slug-less key cannot distinguish two migrations in one release) and uses dashes, never dots, between version segments; directories are update-<ver>/. Key form otherwise follows the file's dominant convention (SKILL.md section 3)
Raw updateJson(tree, 'nx.json', ...)Direct updateJson on nx.jsonreadNxJson / updateNxJson
Raw updateJson on project.jsonupdateJson(tree, join(root, 'project.json'), ...)updateProjectConfiguration; raw edits silently skip package.json-based projects
Returning a GeneratorCallbackPromise<GeneratorCallback> return type, returning install tasksDiscarded by the runner; return void, string[], or { nextSteps, agentContext, skipAgentic }
console.* or the nx output utilconsole.warn(...), import { output } from 'nx/src/utils/output'devkit logger
Static import * as ts from 'typescript'Value import at module topType-only import plus lazy ensureTypescript() / ensurePackage
Deep nx/src/* importsfrom 'nx/src/utils/...' in a plugin migrationUse devkit exports; boundary-crossing imports are tolerated in old code, not in new
Substring checks for ignore filescontent.includes(entry) then string appendaddEntryToGitIgnore (packages/nx/src/utils/ignore.ts)
Non-colocated prompt filesprompt pointing into a generator's files/ directoryColocate the .md in the migration's update-<ver>/ directory
Prompt .md written in the documentation genreh4 #### Sample Code Changes headings in a file wired as promptPrompts use the runbook genre (templates/prompt-runbook.md); the h4 genre is for documentation files
devkit glob in migrationsglob( from @nx/devkitDeprecated in place; use globAsync
Referenced from SKILL.md