Skip to content

Keeping your tooling up to date is a tedious and time-consuming part of maintaining any project. The nx migrate command automates that work by:

  • Updating your package.json dependencies.
  • Updating your configuration files (e.g. Vite, Playwright, Nx config).
  • Updating your source code to match the new versions of packages (e.g., migrating across breaking changes).

The command guides you through the update interactively:

Terminal window
nx migrate

Nx knows where its configuration files are located and ensures they match the expected format. This automated update process is commonly referred to as "migration." Each Nx plugin can provide migrations for its area of competency. For example, the Vite plugin ships migrations that update Vite configuration files across breaking changes. When you run nx migrate, Nx collects the pending migrations from all the plugins you have installed and applies the necessary changes to your workspace.

Updating your Nx workspace happens in two phases:

  1. Generate - nx migrate applies the package version updates to your package.json and writes a migrations.json file. No source code is touched yet.
  2. Run - nx migrate --run-migrations runs the generated migrations to update your configuration files and source code.

You can intervene between the phases and make adjustments as needed for your specific workspaces. This is especially important in large codebases where you might want to control the changes more granularly.

Run the migrate command and follow the prompts:

Terminal window
nx migrate

Nx resolves the latest version and, when the update crosses more than one major version, asks how far to jump. Updating one major version at a time is the safest path and is what Nx recommends.

Nx also asks which package versions to migrate. The answer maps to the --include flag:

  • required - the target package and the packages it ships with. For example, Nx itself and its plugins such as @nx/vite.
  • optional - the dependency updates those packages recommend. For example, vite itself rather than @nx/vite.
  • all - both of the above.

When unsure, choose required. Updating only Nx and its plugins keeps the PR scope small and has less chance of introducing issues, which matters most in large workspaces. Follow up with nx migrate --include=optional to catch up on the rest. If you're okay with doing everything in one PR, use --include=all.

In some cases you can scope the optional catch-up to a single plugin's dependencies, such as nx migrate @nx/vite --include=optional - see choosing which packages to migrate for the caveat.

This results in:

  • The package.json being updated with the new package versions
  • A migrations.json being generated if there are pending migrations.

At this point, no packages have been installed, and no other files have been touched.

Now, inspect package.json to see if the changes make sense. Sometimes the migration can update a package to a version that is either not allowed or conflicts with another package. You are free to adjust versions before running install.

Terminal window
npm install

Also, look at the migrations.json file for the type of migrations that are going to be applied. If this file does not exist, then there are no migrations to run.

Run the migrations that were generated in the previous step (migrations.json):

Terminal window
nx migrate --run-migrations

Migrations run one at a time and contain two types of changes:

  1. Generator-based ("script-based"): programmatic config or code changes (e.g. rollupOptions becomes rolldownOptions in vite.config.ts for Vite 8).
  2. Prompt-based: AI-aided changes that can't be expressed deterministically and need judgment about your specific code.

A migration can be generator-only, prompt-only, or a hybrid (a generator followed by AI-aided changes).

Generator-only migrations run automatically. All the changes are unstaged ready for you to review.

When prompt-only or hybrid migrations are queued and a supported AI agent is installed (Claude Code, OpenAI Codex, or OpenCode), Nx asks whether to continue with an agentic flow. You can answer for this run only, or have Nx remember your choice in nx.json. With the agentic flow enabled:

  • Generator-based changes run first, and the agent validates the results.
  • The agent then applies the prompt-based changes as instructed in the prompt.

Nx creates a commit for each migration while the agentic flow is enabled, so the agent reviews each migration's changes in isolation.

Without an agent, generator-only migrations and the generator half of hybrid migrations still run. The skipped prompt files are listed in the next-steps output, in order, so you can apply them yourself.

After you run all the migrations, you can remove migrations.json and commit any outstanding changes.

Note: You may want to keep the migrations.json until every branch that was created before the migration has been merged. Leaving the migrations.json in place allows devs to run nx migrate --run-migrations to apply the same migration process to their newly merged code as well.

Step 4: Update community plugins (Optional)

Section titled “Step 4: Update community plugins (Optional)”

If you have any Nx community plugins installed you need to migrate them individually (assuming they provide migration scripts) by using the following command:

Terminal window
nx migrate my-plugin

For a list of all the plugins you currently have installed, run:

Terminal window
nx report

Set workspace-wide defaults for nx migrate in the migrate section of nx.json instead of passing the same flags on every run. You can control commit behavior, package selection, multi-major version handling, and the agentic flow:

nx.json
{
"migrate": {
"agentic": "claude-code",
"createCommits": true,
"commitPrefix": "chore(repo): apply nx migration "
}
}

For all available options, see the migrate section of the nx.json reference.

When you run nx migrate, the nx package and all the @nx/ packages get updated to the same version. It is important to keep these versions in sync to have Nx work properly.

As long as you run nx migrate instead of manually changing the version numbers, you shouldn't have to worry about it. Also, when you add a new plugin, use nx add <plugin> to automatically install the version that matches your repository's version of Nx.

Sometimes you need to deviate from the defaults: skip optional package updates and catch them up later, pin a specific AI agent or disable the agentic flow, run migrations one at a time, or opt out of specific migrations by adjusting migrations.json.

Find all of these in our Advanced Update Process guide.