Skip to content

feat: Define Nx migrations strategy and contributing guidelines #703

Description

@nx-plugin-for-aws

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

  1. Wire migrations.json into package.json under the nx-migrations field
  2. Solve version stamping — contributors should not need to manually assign versions; the build/release process handles it automatically
  3. Document the strategy in the contributing guide on the docs site
  4. 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
  5. Document escape hatches: how users can skip specific migrations, how to handle conflicts
  6. Create a section in CONTRIBUTING.md pointing to the full guide

Acceptance Criteria

  • migrations.json wired into package.json nx-migrations field
  • Version stamping solved — contributors don't manually assign versions
  • Contributing guide documents what is/isn't in scope for migrations
  • Decision tree or flowchart for "should this be a migration?"
  • Examples of good migrations vs. things that should NOT be migrations
  • Dependency update strategy documented (minor/patch automation, major version process)
  • Clear guidance on when a dependency bump needs a migration vs. when it doesn't
  • Documentation published on the docs site (English only)

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or requestv1.0Roadmap to v1.0 stable release

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions