With the Angular CLI, what does `ng update @angular/core @angular/cli` do beyond changing version numbers in package.json?
answer
- resolve, validate, install, migrate
- package groups move together
- peer dependency check before install
- clean git working tree required
- migrations between old and new version
basics
~20 sng 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 linesgit 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 diffgo deeper
Know that ng update bumps Angular packages and also runs code migrations, and that you commit before running it.
Walk through the pipeline: clean-tree check, package groups, peer validation, install with rollback, and migrations run between the old and new version.
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.
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