Description
Define and document a clear strategy for Nx migrations in the @aws/nx-plugin. This strategy should guide contributors on what should and shouldn't be handled via automated migrations when breaking changes are introduced between versions.
Motivation
As we approach v1.0, the plugin will need a reliable migrations story. Nx supports migrations.json in plugins which allows nx migrate to automatically apply code transformations when users upgrade. Without clear guidelines, contributors will either:
- Skip migrations entirely (leaving users with broken upgrades)
- Over-reach with migrations (overwriting user-customized files like
agent.py or custom CDK constructs)
Scope Definition
Migrations SHOULD cover:
- Changes to generator metadata in
project.json (e.g., renamed targets, updated options)
- Updates to shared constructs in
packages/common/ that follow known patterns
- AST-level patches to files that follow a predictable structure (e.g., updating import paths, renaming exported symbols)
- Configuration file updates (
aws-nx-plugin.config.mts, nx.json sync generator entries)
- Dependency version bumps in
package.json / pyproject.toml
- Renaming of generator IDs (updating
project.json metadata references)
Migrations SHOULD NOT cover:
- User-authored business logic (e.g., custom
agent.py, custom CDK stacks beyond the generated scaffold)
- Files where the generator only provides initial scaffolding and the user is expected to modify heavily
- Stylistic or formatting changes
- Optional enhancements that didn't exist in the prior version
Dependency Update Strategy
The plugin vends dependencies to users' projects (e.g., TypeScript, Vite, tRPC, Zod, CDK, FastAPI, Strands SDK, etc.). The strategy must cover how these are managed:
Automated minor/patch updates:
- The plugin already has an
update-versions workflow that bumps vended dependency versions
- When a dependency is bumped and no code changes are required in user projects, the version bump itself is sufficient — users get the new version next time they install
- When a dependency bump requires code changes (e.g., new API, deprecated method removed), a migration must accompany the version bump
- The strategy should define how to detect whether a dependency bump needs a migration (e.g., automated CI check that generates a project at the old version, bumps deps, and runs build/lint/tests)
Manual major version updates (e.g., TypeScript 7, Vite 9, React 20):
- Major version upgrades often require code changes in generated files
- The strategy should define the process: upgrade locally, identify required changes via
git diff, write a migration that applies those changes
- Some major upgrades may require changes to user-owned files — these should log warnings rather than auto-patching
Automating migration generation for dependency bumps:
- If the
update-versions workflow bumps a dependency and no code changes are needed, no migration is required (just a version bump in the vended package.json / pyproject.toml)
- If code changes ARE needed, the workflow should either:
- Fail CI, signaling that a migration is required before the bump can land
- Or auto-generate a migration that bumps the version in user projects' dependency files
- The simplest case (most common): a migration that just updates the version string in
package.json / pyproject.toml — this could potentially be automated entirely
Key Design Problem: Version Targeting
The project uses conventional commits with automatic semver — the next version number isn't known until the release pipeline runs. Nx requires a concrete "version" in migrations.json to know when to run a migration (it runs migrations where installed_version < migration_version).
Current release model (important context):
package.json stays at "version": "0.0.0" in source — version is never committed
nx.json release config uses currentVersionResolver: "git-tag" and manifestRootsToUpdate: ["dist/{projectRoot}"]
- The release workflow (
pnpm nx release --yes) calculates the version, writes it to dist/, creates a git tag, and publishes — no source commit is made
- Tags point directly at the last merged commit
This means contributors cannot manually set migration versions. The solution must automatically determine the correct version at build/release time without requiring CI workflow changes or automated PRs back to source.
Possible approach: derive versions from git history at compile time
Source migrations.json entries have no version fields. The compile step stamps them:
- For migrations that already shipped (file existed in a previous tag): use that tag's version
- For migrations that haven't shipped yet: use
latest_tag + 0.0.1 (or similar bump)
This works because Nx runs migrations where version > installed_version, so any version between the user's current and the new version qualifies. No workflow changes, no automated PRs — git history is the source of truth.
This is a suggestion — the actual implementation should be determined when this work is picked up.
Suggested Implementation
- Wire
migrations.json into package.json under the nx-migrations field
- Solve version stamping — contributors should not need to manually assign versions; the build/release process handles it automatically
- Document the strategy in the contributing guide on the docs site
- Define a decision tree for contributors:
- "Is this a breaking change?" → If yes, a migration is required
- "Does the file follow a predictable pattern?" → If yes, use AST patching
- "Is the file user-owned (heavily customized)?" → If yes, emit a warning/log instead of modifying
- Document escape hatches: how users can skip specific migrations, how to handle conflicts
- Create a section in CONTRIBUTING.md pointing to the full guide
Acceptance Criteria
Description
Define and document a clear strategy for Nx migrations in the
@aws/nx-plugin. This strategy should guide contributors on what should and shouldn't be handled via automated migrations when breaking changes are introduced between versions.Motivation
As we approach v1.0, the plugin will need a reliable migrations story. Nx supports
migrations.jsonin plugins which allowsnx migrateto automatically apply code transformations when users upgrade. Without clear guidelines, contributors will either:agent.pyor custom CDK constructs)Scope Definition
Migrations SHOULD cover:
project.json(e.g., renamed targets, updated options)packages/common/that follow known patternsaws-nx-plugin.config.mts,nx.jsonsync generator entries)package.json/pyproject.tomlproject.jsonmetadata references)Migrations SHOULD NOT cover:
agent.py, custom CDK stacks beyond the generated scaffold)Dependency Update Strategy
The plugin vends dependencies to users' projects (e.g., TypeScript, Vite, tRPC, Zod, CDK, FastAPI, Strands SDK, etc.). The strategy must cover how these are managed:
Automated minor/patch updates:
update-versionsworkflow that bumps vended dependency versionsManual major version updates (e.g., TypeScript 7, Vite 9, React 20):
git diff, write a migration that applies those changesAutomating migration generation for dependency bumps:
update-versionsworkflow bumps a dependency and no code changes are needed, no migration is required (just a version bump in the vendedpackage.json/pyproject.toml)package.json/pyproject.toml— this could potentially be automated entirelyKey Design Problem: Version Targeting
The project uses conventional commits with automatic semver — the next version number isn't known until the release pipeline runs. Nx requires a concrete
"version"inmigrations.jsonto know when to run a migration (it runs migrations whereinstalled_version < migration_version).Current release model (important context):
package.jsonstays at"version": "0.0.0"in source — version is never committednx.jsonrelease config usescurrentVersionResolver: "git-tag"andmanifestRootsToUpdate: ["dist/{projectRoot}"]pnpm nx release --yes) calculates the version, writes it todist/, creates a git tag, and publishes — no source commit is madeThis means contributors cannot manually set migration versions. The solution must automatically determine the correct version at build/release time without requiring CI workflow changes or automated PRs back to source.
Possible approach: derive versions from git history at compile time
Source
migrations.jsonentries have no version fields. Thecompilestep stamps them:latest_tag + 0.0.1(or similar bump)This works because Nx runs migrations where
version > installed_version, so any version between the user's current and the new version qualifies. No workflow changes, no automated PRs — git history is the source of truth.This is a suggestion — the actual implementation should be determined when this work is picked up.
Suggested Implementation
migrations.jsonintopackage.jsonunder thenx-migrationsfieldAcceptance Criteria
migrations.jsonwired intopackage.jsonnx-migrationsfield