Angular Upgrade Planner
Pick a source and target Angular version (8–22) for an ordered, checkable upgrade plan — ng update commands, breaking changes, deprecations, and migrations.
Choose your upgrade path
Angular 19 → Angular 20
(7 steps)Commit or stash all work, then make sure you are on the latest minor/patch of your current major before running ng update. Upgrade exactly one major at a time and run the app/tests after each hop.
Angular 20 requires Node.js 20.19+, 22.12+, or 24, and TypeScript 5.8 (up to <6.0). Node 18 and TypeScript 5.7 and below are no longer supported.
Check your Node.js & TypeScript versions for Angular 20 →Update the core framework and CLI together. This applies the official automatic migration schematics for this version.
ng update @angular/core@20 @angular/cli@20
The DOCUMENT token moved from @angular/common to @angular/core. The ng update migration rewrites the imports automatically.
The structural directives are deprecated in favor of built-in control flow (@if/@for/@switch). They still ship in Angular 22, marked for removal in a future major. Run the control-flow migration. TestBed.get() is removed (auto-migrated to TestBed.inject()), and TestBed.flushEffects() is deprecated in favor of TestBed.tick().
Convert a template to @if/@for online →ng generate @angular/core:control-flow
The compiler can now type-check host bindings and @HostBinding/@HostListener expressions. It is opt-in in v20 via typeCheckHostBindings in angularCompilerOptions, and becomes the default in v21, so enabling it now surfaces errors early.
effect(), linkedSignal() and toSignal() are now stable, completing the core signal APIs. Zoneless change detection moves to developer preview and provideExperimentalZonelessChangeDetection is renamed provideZonelessChangeDetection.
Sources: Angular Update Guide: v19 → v20 · Angular 20.0.0 release notes · Announcing Angular v20 (Angular Blog)
Angular 20 → Angular 21
(9 steps)Commit or stash all work, then make sure you are on the latest minor/patch of your current major before running ng update. Upgrade exactly one major at a time and run the app/tests after each hop.
Angular 21 requires Node.js 20.19+, 22.12+, or 24, and TypeScript 5.9 (up to <6.0).
Check your Node.js & TypeScript versions for Angular 21 →Update the core framework and CLI together. This applies the official automatic migration schematics for this version.
ng update @angular/core@21 @angular/cli@21
Applications are zoneless unless they provide Zone.js change detection. The ng update migration adds provideZoneChangeDetection() to existing apps so they keep working; review code that relies on Zone.js patching before removing it.
New projects use Vitest. Existing projects keep Karma, which is still supported (new projects can opt in with --test-runner=karma). The experimental Jest and Web Test Runner builders are slated for removal in v22.
Convert Jasmine specs to Vitest online →typeCheckHostBindings is now on by default, so invalid host binding and @HostBinding/@HostListener expressions become compile errors. Fix what the compiler flags, or turn the option off temporarily.
HttpClient is available from the root injector without calling provideHttpClient(). Keep provideHttpClient() when you need interceptors or features such as withFetch().
Angular now recommends native [class] and [style] bindings over NgClass and NgStyle, and provides migrations for both.
ng generate @angular/core:ngclass-to-class
Signal Forms ship as an experimental API — a signal-based alternative to reactive forms. Try it in non-critical areas; it becomes stable in v22.
Sources: Angular Update Guide: v20 → v21 · Angular 21.0.0 release notes · Announcing Angular v21 (Angular Blog)
Angular 21 → Angular 22
(10 steps)Commit or stash all work, then make sure you are on the latest minor/patch of your current major before running ng update. Upgrade exactly one major at a time and run the app/tests after each hop.
Angular 22 requires TypeScript 6.0 (5.9 and below are no longer supported) and Node.js ^22.22.3, ^24.15.0 or ^26.0.0. Node 20 is dropped, and earlier Node 22/24 releases are below the minimum. Upgrade your toolchain before updating.
Check your Node.js & TypeScript versions for Angular 22 →Update the core framework and CLI together. This applies the official automatic migration schematics for this version.
ng update @angular/core@22 @angular/cli@22
A component without changeDetection now uses OnPush, and the old Default strategy is renamed Eager. The ng update migration adds changeDetection: ChangeDetectionStrategy.Eager to existing components, so behavior is preserved. Remove Eager component by component as you move to signals.
Route parameters and data are now inherited from all parent routes by default. There is no migration: set paramsInheritanceStrategy: 'emptyOnly' in withRouterConfig() to keep the old behavior, or review components that read route params/data.
HttpClient now uses fetch instead of XMLHttpRequest. The migration removes withFetch() calls, or adds withXhr() where you need XHR behavior such as upload progress events. reportProgress is deprecated in favor of reportUploadProgress and reportDownloadProgress.
In templates, a?.b now returns undefined instead of null when a is null or undefined, matching TypeScript. The migration wraps affected expressions in $safeNavigationMigration() to keep the old result; check code that compares with === null.
strictTemplates is enabled by default, so stricter template type errors can appear. canMatch guards receive a required currentSnapshot parameter (migrated automatically). The experimental Jest and Web Test Runner builders are removed.
Signal Forms are stable, resource()/rxResource()/httpResource() are production-ready, and the @angular/aria headless accessibility package leaves developer preview.
Reactive Forms → Signal Forms reference →@Service() is a shorter @Injectable({ providedIn: 'root' }) for classes that use inject(). It doesn't support constructor injection, so migrate constructors first, then switch services. @Injectable still works, so this is optional.
Convert constructors to inject() and @Service() online →ng generate @angular/core:inject ng generate @angular/core:service
Sources: Angular Update Guide: v21 → v22 · Angular 22.0.0 release notes · Announcing Angular v22 (Angular Blog)
Tip: Upgrade one major at a time and run ng update for each hop — it applies the official migration schematics automatically. Commit between hops and run your tests. This is a representative checklist of the major changes; always confirm specifics against the official Angular Update Guide for your exact versions.
Upgrading Angular 19 to Angular 22
This plan covers the full path from Angular 19 to Angular 22 — 3 version hops and 26 steps in total. Upgrade one major at a time, running ng update for each hop so the official migration schematics apply. Commit and run your tests between hops.
Breaking changes to check between Angular 19 and Angular 22
- Zoneless change detection is the default (Angular 20 → Angular 21): Applications are zoneless unless they provide Zone.js change detection. The ng update migration adds provideZoneChangeDetection() to existing apps so they keep working; review code that relies on Zone.js patching before removing it.
- Vitest replaces Karma as the default test runner (Angular 20 → Angular 21): New projects use Vitest. Existing projects keep Karma, which is still supported (new projects can opt in with --test-runner=karma). The experimental Jest and Web Test Runner builders are slated for removal in v22.
- Host bindings are type-checked by default (Angular 20 → Angular 21): typeCheckHostBindings is now on by default, so invalid host binding and @HostBinding/@HostListener expressions become compile errors. Fix what the compiler flags, or turn the option off temporarily.
- OnPush is the default change detection strategy (Angular 21 → Angular 22): A component without changeDetection now uses OnPush, and the old Default strategy is renamed Eager. The ng update migration adds changeDetection: ChangeDetectionStrategy.Eager to existing components, so behavior is preserved. Remove Eager component by component as you move to signals.
- Route paramsInheritanceStrategy defaults to 'always' (Angular 21 → Angular 22): Route parameters and data are now inherited from all parent routes by default. There is no migration: set paramsInheritanceStrategy: 'emptyOnly' in withRouterConfig() to keep the old behavior, or review components that read route params/data.
- HttpClient uses the Fetch API by default (Angular 21 → Angular 22): HttpClient now uses fetch instead of XMLHttpRequest. The migration removes withFetch() calls, or adds withXhr() where you need XHR behavior such as upload progress events. reportProgress is deprecated in favor of reportUploadProgress and reportDownloadProgress.
- Template optional chaining returns undefined (Angular 21 → Angular 22): In templates, a?.b now returns undefined instead of null when a is null or undefined, matching TypeScript. The migration wraps affected expressions in $safeNavigationMigration() to keep the old result; check code that compares with === null.
Hops in this path
- Angular 19 → Angular 20 — 7 steps
- Angular 20 → Angular 21 — 9 steps
- Angular 21 → Angular 22 — 10 steps
Before you start
- Commit or stash your work and upgrade on a branch so you can roll back.
- Get on the latest minor/patch of Angular 19 before the first hop.
- Update third-party libraries (including Angular Material/CDK) alongside each hop, and run your tests after each one.
Sources
Every step in this plan is checked against Angular's official documentation and release notes. Last reviewed .
- Angular Update Guide: v19 → v20
- Angular 20.0.0 release notes
- Announcing Angular v20 (Angular Blog)
- Angular Update Guide: v20 → v21
- Angular 21.0.0 release notes
- Announcing Angular v21 (Angular Blog)
- Angular Update Guide: v21 → v22
- Angular 22.0.0 release notes
- Announcing Angular v22 (Angular Blog)
- Angular version compatibility (Node.js, TypeScript, RxJS)
- Angular Update Guide