
Angular 20 brings a wide range of updates: improvements to reactivity, SSR, support for zoneless architecture, template syntax enhancements, better tooling, and more.
Below is a categorized breakdown of all the changes:
At the end, I’ll share some of my personal highlights 👇
effect, linkedSignal, toSignal are now stable APIs.incremental hydration and route-level rendering mode config have also
reached stable status.unhandledRejection, uncaughtException).resource API to trigger async operations from signals.streamingResource for working with WebSocket streams.httpResource wraps HttpClient in a reactive, signal-based API.llms.txt file to help LLMs generate up-to-date Angular code.@defer blocks, hydration state, and zones.trackFn calls, ?? misuse, missing
imports, etc.createComponent Enhancementsbindings, directives, and two-way binding.** (exponentiation), in operator, and untagged template
literals.host object.typeCheckHostBindings flag in tsconfig.json.Component, Service, Pipe are now optional.*ngIf, *ngFor, and *ngSwitch are now deprecated. New control flow syntax
@if, @for, @switch is preferred. Migration command:
ng generate @angular/core:control-flowI've often run into issues with Zone.js—from odd side effects during state
updates to unpredictable behavior due to monkey-patching. On the server, it's
even worse, causing memory leaks in Node.js and hard-to-trace crashes.
Now, you can bootstrap your app without Zone.js using:
bootstrapApplication(AppComponent, {
providers: [
provideZonelessChangeDetection(),
provideBrowserGlobalErrorListeners()
]
});Just make sure to remove the zone.js polyfill from angular.json. This
greatly simplifies debugging and SSR stability.
createComponent APICreating dynamic components used to be verbose. Now, it’s all declarative:
createComponent(MyDialog, {
bindings: [
inputBinding('canClose', signal(true)),
outputBinding('onClose', (result) => console.log(result)),
twoWayBinding('title', signal('Dialog Title'))
],
directives: [FocusTrap]
});This is a major improvement, especially for UI library authors. It unlocks powerful use cases. It is like host directives, but in runtime and dynamic.
@HostBinding and @HostListener were convenient, but the main problem for me
was that they don't work with signals and Observables. Now you can express this
clearly in the host object with full editor support:
@Component({
host: {
'[class.active]': 'isActive()',
'(click)': 'handleClick()',
}
})And now with typeCheckHostBindings enabled:
{
"angularCompilerOptions": {
"typeCheckHostBindings": true
}
}You get type safety and better DX.
*ngIf, *ngFor, *ngSwitchThis was long overdue. The new control flow syntax is simpler, closer to
JavaScript, and removes the need to import CommonModule.
Migration is easy:
ng generate @angular/core:control-flowFrom this:
<div *ngIf="user">{{ user.name }}</div>To this:
@if (user) {
<div>{{ user.name }}</div>
}Cleaner, more readable, fewer surprises.
This was a solid release. Of course, as developers, we always wish new features were stabilized faster and shipped more frequently — but that doesn't make us any less excited for the next major in six months or the RFCs in between.
Meanwhile, minor releases might still bring exciting updates. And yes, we’re looking at you, signal-based forms ✌️
🟢 Course updates on ng.guide will go live as soon as Nx 20 adds support for Angular 20.
🎁 Pre-order now — "Angular UI Kit"
We’re launching our first interactive course on ng.guide, where you'll build a production-grade UI library using real-world Angular practices.
💸 Early-bird price: $99 (was $125) — available only before launch.
Reserve your access now and get hands-on with how Angular works at scale.