Angular 21 removed the old guard — Karma out, zone.js optional. Angular 22 goes further: it changes what a default component is.
For the first time, OnPush is the default change detection strategy, route parameters flow down the whole tree, and the framework doubles down on being agent-friendly infrastructure. Here is what breaks, and how to fix it.
TL;DR — upgrade Angular 21 to 22 in 4 steps:
node --version # must be 22+ (Node 20 is no longer supported) npm install -g @angular/cli@latest ng update @angular/core@22 @angular/cli@22 ng testThe three changes most likely to hit you: OnPush is the new default change detection (a migration adds
ChangeDetectionStrategy.Eagerto your existing components), route params now inherit with'always'instead of'emptyOnly', and Node 22 + TypeScript 6.0 are the new minimums. Details and fixes below.
🚨 The “Stop Everything” Breaking Changes
1. OnPush Is the Default Now
This is the philosophical headline of v22. A component that doesn’t set changeDetection used to mean “check me on every cycle.” In Angular 22 it means ChangeDetectionStrategy.OnPush.
What breaks: Nothing in your existing code — if you let the migration do its job. ng update adds the new ChangeDetectionStrategy.Eager value (the old check-always behavior, now with a name) to every component that relied on the old default.
What actually changes: Every new component you generate is OnPush. If your team’s habits still assume mutation-based updates (“I changed the property, why didn’t the view update?”), v22 is where those habits die.
The Fix:
- Let the automatic migration stamp
Eageron legacy components. Don’t fight it during the upgrade. - For new code, embrace signals —
signal(),computed(), andinput()make OnPush invisible because updates are tracked at the value level. - Migrate old components off
Eagerincrementally. The Angular MCP server’sonpush_zoneless_migrationtool analyzes a component’s dependency graph before you flip the strategy — I covered it in the Angular MCP guide.
2. Route Params Inherit Everywhere
The router’s paramsInheritanceStrategy default changed from 'emptyOnly' to 'always'.
What breaks: Child routes now see every parent route’s params and data. If a child route reads a param name that also exists on a parent (:id on both a parent and child, for example), it may now resolve to a value it never saw before. Components with defensive “param is undefined” branches may silently take the other branch.
The Fix: Audit components that read route params or data. If you need the old behavior back, it’s one line:
provideRouter(routes, withRouterConfig({
paramsInheritanceStrategy: 'emptyOnly',
}))Prefer renaming colliding params (:userId vs :orderId) over reverting globally — the 'always' default is genuinely better for deep-linked detail pages.
3. Node 22 and TypeScript 6.0 Are Mandatory
What breaks: The build, immediately, if your CI or local environment runs Node 20 (now past end-of-life) or TypeScript 5.9.
The Fix: Upgrade Node to 22, 24, or 26 and TypeScript to 6.0+ before running ng update. Check your CI images, your Dockerfiles, and your engines field — the local upgrade is always the easy half.
4. Smaller Sharp Edges
- Duplicate input bindings are a compile error. Binding the same input twice on one element used to be silently tolerated; now the template compiler rejects it.
data-*attributes are no longer treated as property bindings — they bind as attributes, which is what you almost certainly wanted anyway.- The HTTP transfer cache skips credentialed requests by default (cookie-bearing and
withCredentials), so authenticated responses can’t leak across SSR sessions. If you relied on caching those, you now have to opt in deliberately.
✨ The New Toys: Features You’ll Actually Use
Signal Forms Are Stable
The experimental warnings are gone. The form()/field() model from v21 is now the blessed, typed, signal-first way to build forms. If you held off adopting them in 21, v22 is the green light.
resource() and httpResource Are Production-Ready
Async data as a signal, with loading and error states built in. Together with stable Signal Forms and OnPush-by-default, the signal-first architecture is no longer “the direction Angular is heading” — it’s just how Angular works.
Selectorless Components
Import a component and use it in the template directly — no string selector indirection, better type safety, easier refactoring.
The Agentic Story Continues
v22 extends the MCP + Skills stack introduced around v21: the CLI’s MCP server plus the skills layer that teaches agents to write signal-first, OnPush-correct code. I’ve written about this in depth: agent-safe component patterns and exhaustive types for hallucination-free agents.
Summary: The Checklist
- Node 22+, TypeScript 6.0+ — environment first.
ng update @angular/core@22 @angular/cli@22and let theEagermigration run.- Audit route param reads (or pin
'emptyOnly'back). - Run the test suite; fix duplicate input bindings the compiler now flags.
- Adopt Signal Forms and
resource()in new code; peel components offEagerover time.
The official interactive checklist lives at angular.dev/update-guide, and the release announcement at angular.dev/events/v22.
Coming from an older version? Start with Angular 20 to 21: Breaking Changes and How to Fix Them, or see every migration path in the Angular Upgrade Guide.
