Angular
Signals and zoneless mode in Angular 22: what changes for an existing application
Zoneless mode removes automatic change detection. In practice, that exposes useless renders and forces a rethink of how state moves through the application.
For years, change detection in Angular rested on a simple rule: any completed asynchronous task triggered a check of the component tree. Convenient, but costly: an HTTP request, a timer or a socket event could trigger a check with no visible effect.
Angular 22 makes zoneless mode production-ready. Is it a good idea on an existing application? Yes, provided the migration is treated as architecture work rather than a configuration change.
What zoneless mode really changes
Without zone.js, Angular no longer knows that data has changed: you have to tell it. Signals do that job, but only inside the signal system. An object mutated after a classic network call will not trigger a render. That is not a flaw: it is exactly what makes behaviour predictable.
@Component({
selector: 'app-order-list',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class OrderListComponent {
private readonly ordersService = inject(OrdersService);
readonly filter = signal<OrderFilter>({ status: 'OPEN', page: 0 });
readonly orders = toSignal(
toObservable(this.filter).pipe(
switchMap(filter => this.ordersService.search(filter)),
),
{ initialValue: [] as Order[] },
);
readonly total = computed(() =>
this.orders().reduce((sum, order) => sum + order.amount, 0),
);
onStatusChange(status: OrderStatus): void {
this.filter.update(current => ({ ...current, status }));
}
}
Migrate in stages rather than all at once
The migration we apply runs in four stages, in this exact order, with every stage shippable to production.
- Enable explicit change detection on the most heavily used components.
- Convert local state into signals, starting with filters and counters.
- Replace manual subscriptions with derived signals, removing each explicit change detection call.
- Remove zone.js from application bootstrap and monitor the most complex screens.
The trap of updates coming from outside
Third-party libraries and some browser APIs remain outside the signal system: map event handlers, video players, wrapped websockets. Every external entry point must be explicitly converted to a signal, otherwise the screen will silently freeze. Listing those points before starting avoids a long and frustrating debugging phase.
Server-side rendering and zoneless mode
Server-side rendering benefits directly from this change. The server waits for the application to be stable before sending the page; without zone.js, that stability depends only on signals and in-flight requests, which removes needless waiting. On the back end, paging and filtering must stay server-side to take advantage of it.
@GetMapping("/orders")
Page<OrderResponse> search(@Valid OrderSearchCriteria criteria, Pageable pageable) {
return orderSearch.search(criteria, pageable).map(OrderResponse::from);
}
| Practice | With zone.js | In zoneless mode |
|---|---|---|
| Update after an HTTP call | Automatic | Explicit through a signal |
| Cost of an event with no visible effect | Full tree check | No check at all |
| State shared between components | Often a subject per component | Signal provided by a service |
| Diagnosing a frozen screen | Rare | A forgotten external entry point |
Zoneless mode does not make an application fast: it makes every update triggered for nothing visible.
Measure before generalising
We measure three indicators before and after migration: interaction time on list screens, the number of render cycles on a repeatable scenario, and server render stabilisation time. Those measurements decide whether to continue with the remaining screens or stop at an intermediate scope.
On the applications we have supported, the clearest gain does not come from zoneless mode itself but from the cleanup it forces: unreleased subscriptions, duplicated state, and components resubscribing on every interaction. That work is what produces the measurable difference.
Related articles
Observability with OpenTelemetry: instrument what actually helps diagnosis
Adding a tracing library does not make a system observable. What matters is attribute choice, context propagation and discipline about stored volumes.