skip to content

Update Command & Migrations

ng update bumps Angular and third-party packages, then runs their migrations against your code and logs each change. Interviewers ask how to move a real app across majors safely.

part ofAngular CLIoverview, primer and where to startread it →
on this pageshow

explore

questions

5

With the Angular CLI, what does `ng update @angular/core @angular/cli` do beyond changing version numbers in package.json?

level: juniorimportance: must knowfreq 66%

answer

  1. resolve, validate, install, migrate
  2. package groups move together
  3. peer dependency check before install
  4. clean git working tree required
  5. migrations between old and new version

basics

~20 s

ng update resolves compatible target versions for the named packages and their package groups, checks peer dependencies, requires a clean git tree, rewrites package.json, installs, then runs each updated package's migration schematics to change your code and configuration.

solid answer

~40 s

`ng update` is an update *and* a code migration. It first refuses to run on a repository with uncommitted changes unless you pass `--allow-dirty`, so the update's diff stays separate. It resolves target versions: a package's `ng-update.packageGroup` pulls its siblings along, so updating `@angular/core` also moves `@angular/common`, `@angular/router`, `@angular/forms` and the rest. It validates peer dependencies across the whole plan and stops on conflicts unless you pass `--force`. For Angular packages it refuses to jump more than one major. It writes `package.json` and installs, restoring `package.json` if the install fails. Then, for every updated package that declares `ng-update.migrations`, it runs the migration schematics whose versions lie after the old version and up to the new one, logging each file it changes. Running `ng update` with no arguments only lists what can be updated.

code

bash · 4 lines
bash
git status                                  # must be clean
ng update                                   # see what supports ng update
ng update @angular/core@22 @angular/cli@22
ng build && ng test                         # then review and commit the diff

go deeper

for a junior

Know that ng update bumps Angular packages and also runs code migrations, and that you commit before running it.

for a middle

Walk through the pipeline: clean-tree check, package groups, peer validation, install with rollback, and migrations run between the old and new version.

for a senior

Plan updates around the pipeline: which packages to name together, reading peer errors and migration logs, and verifying the result with build and tests before merging.

for a principal

Decide how often the organisation takes majors and minors, and how shared libraries are kept compatible so ng update is never blocked for long.

## More than a version bump A plain `npm install @angular/core@22` changes one version and leaves your code as it was. Angular majors come with breaking changes, deprecated APIs and new defaults, so the CLI's `ng update` combines three jobs: **choosing consistent versions**, **installing them**, and **rewriting your code** with migrations shipped by the packages themselves. ## The steps, in order 1. **Clean repository check.** When you name packages, the CLI checks `git status`. With uncommitted changes it stops: `Repository is not clean. Please commit or stash any changes before updating.` `--allow-dirty` overrides this with a warning. The point is that the update's changes can be reviewed and reverted on their own. 2. **Right CLI for the job.** If the installed CLI does not match the version needed to run the update, for example when you ask for `@angular/core@22` from a v21 workspace, the CLI installs a temporary `@angular/cli` of the target major and re-runs the command with it. The migrations then run with a matching schematics runtime. 3. **One major per step.** For `@angular/*` packages, a jump of more than one major is rejected with a message telling you which `ng update <pkg>@<next major>` to run instead. 4. **Resolve the plan.** Each package's `ng-update.packageGroup` adds its siblings: `@angular/core`'s group covers the framework packages, and `@angular/cli`'s group covers `@angular/build`, `@angular/ssr` and the devkit packages. 5. **Validate peer dependencies** across every package in the plan, in both directions: what the updated packages require, and what installed packages require of them. On a conflict it prints `Package "x" has an incompatible peer dependency to "y" (requires ..., would install ...)` and stops, suggesting `--force`. 6. **Write and install.** It updates `package.json`, cleans `node_modules` when the package manager is npm, and installs. If the install fails, it restores the original `package.json`. 7. **Run migrations.** For every updated package whose `package.json` declares `ng-update.migrations`, it runs the migration schematics whose `version` is greater than the old version and no greater than the new one. Required migrations run automatically; optional ones are offered in a prompt. Each logs what it changed. ## What you see and what you get | Output | Meaning | |---|---| | `Using package manager: ...` | Detected npm, pnpm, yarn or bun | | `Fetching dependency metadata from registry...` | Resolving target versions | | `** Executing migrations of package '@angular/core' **` | Migrations for that package start | | `Migration completed (N files modified).` | One migration's result | | `This package has N optional migrations...` | Optional migrations to choose from | The result is a working tree with new versions and migrated code. It is ready to build, test and commit, or already committed step by step with `--create-commits`. ## `ng update` with no packages Run on its own, `ng update` changes nothing. It prints `We analyzed your package.json, there are some packages to update:` followed by a table of packages that support `ng update`: name, installed to available version, and the exact command to run. Angular packages more than one major behind are offered only the next major. It also warns that packages without `ng update` support may be outdated too. ## Why this matters in practice - **Migrations only run through `ng update`** (or `--migrate-only`). Bumping versions with a package manager or a dependency bot skips them, and the code is left on APIs the new version removed. - **Package groups prevent mixed versions.** A project with `@angular/core` 22 and `@angular/router` 21 is a support nightmare; the group rule makes that hard to create. - **The peer check is a gate.** It catches third-party libraries that are not ready for the new major before anything is installed. ## Typical commands ```bash ng update # list what can be updated ng update @angular/core@22 @angular/cli@22 # framework + CLI to the latest 22.x ng update @angular/cli@^22 @angular/core@^22 --create-commits ``` The CLI's own help text recommends the caret form (`@^22`) so you land on the latest patch of the target major.

  • Why do you name both `@angular/core` and `@angular/cli`?
    They belong to different package groups and ship different migrations. `@angular/core`'s group moves the framework packages and runs framework code migrations. `@angular/cli`'s group moves `@angular/build`, `@angular/ssr` and the devkit, and runs workspace and build-configuration migrations from `@schematics/angular`. Naming one leaves the other group behind.
  • What happens to a third-party library during `ng update @angular/core`?
    It is not updated unless you name it, but its peer dependencies are checked against the plan. If its declared range rejects the new framework version, the update stops before installing. If you name it and it has `ng-update` metadata, its own migrations run too.

saying these in an interview costs you the question

  • Thinks ng update only edits version numbers in package.json
  • Updates Angular with a plain npm install and skips the migrations
  • Believes ng update core updates only @angular/core, not the framework group
  • Runs ng update on a dirty tree with --allow-dirty by habit
  • Expects ng update with no arguments to update everything
open as a page

Why does the Angular CLI refuse to update `@angular/core` from v20 straight to v22, and how do you move an app across several majors?

level: middleimportance: must knowfreq 62%

basics

~10 s

Migrations and deprecation windows assume one major at a time, so ng update refuses bigger jumps for @angular/* packages. Run ng update @angular/core@^21 @angular/cli@^21, build, test and commit, then repeat for ^22.

open as a page

With the Angular CLI, when do you run `ng update <package> --migrate-only --from <version>`, and how does it differ from a normal `ng update`?

level: middleimportance: should knowfreq 32%

basics

~20 s

Use it when versions were bumped outside ng update (a package manager, a bot, a shared catalog), so migrations never ran. It installs nothing and runs migrations above --from up to --to, which defaults to the installed version.

open as a page

When `ng update @angular/core@22` stops with 'Incompatible peer dependencies found' because a third-party library only accepts Angular 21, how do you resolve it and when is `--force` acceptable?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Name a library release that accepts Angular 22 in the same ng update; without one, wait, replace or patch the library. --force only skips the CLI's check, so use it only after proving the library works on 22.

open as a page

What do the Angular CLI's `ng update` flags `--create-commits` and `--allow-dirty` change, and why does a clean working tree matter?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

--create-commits (-C) commits the version changes, then each migration separately with its name and description. --allow-dirty lets the update run with uncommitted changes, which it otherwise refuses, at the cost of mixing your edits into the update's diff.

open as a page