All topics
Performanceadvanced

Zone.js and Zoneless Change Detection

Explain what Zone.js does, why Angular has relied on it, and what zoneless change detection changes.

Zone.js is a library Angular has relied on since its early versions to automatically know when to run change detection: it monkey-patches nearly every async browser API (setTimeout, addEventListener, Promise callbacks, XHR completion) so that Angular can be notified whenever any of them fire, without the developer needing to manually tell Angular "something happened, please re-check the UI." This is genuinely convenient — it's why a plain setTimeout callback that changes a component property just works and updates the view without any explicit trigger — but it comes at a real cost: Zone.js's blanket monkey-patching means Angular conservatively re-checks broad swaths of the component tree on virtually any async event, whether or not that event actually affected anything visible.

Zone.js is like a building-wide intercom system that announces every single door opening anywhere in the building, prompting security to walk over and check regardless of whether that specific door actually needed attention; zoneless change detection is like replacing that with individual sensors on only the doors that matter, each one directly alerting exactly the right person the instant it actually opens.

Key Concepts

1
Zoneless change detection (stable as of Angular 18, via provideExperimentalZonelessChangeDetection() moving toward stable APIs in subsequent releases) removes Zone.js from the picture entirely, relying instead on Signals' precise, fine-grained dependency tracking to know exactly what changed and exactly which parts of the UI depend on it — no monkey-patching, no conservative "re-check everything" fallback, and a smaller overall JavaScript bundle since Zone.js itself doesn't need to be shipped.
provideExperimentalZonelessChangeDetection()
2
The trade-off, and the reason zoneless isn't simply switched on for every app overnight, is that it requires your application's state changes to actually go through mechanisms Angular can observe — Signals, or explicitly calling ChangeDetectorRef.markForCheck() — rather than relying on Zone.js's implicit "any async callback triggers a check" safety net; code that mutates component state inside a raw setTimeout or a non-Angular-aware third-party callback without using a Signal or manually marking for check simply won't be picked up automatically anymore.
ChangeDetectorRef.markForCheck()setTimeout
3
A forward-looking interview answer frames this as part of a clear, multi-year direction Angular has been building toward: Signals, standalone components, and now zoneless change detection are all pieces of the same broader shift toward a leaner, more explicit, more fine-grained reactive model, replacing several of Angular's original "magic," broadly-applied mechanisms (NgModules, Zone.js) with narrower, more precisely-scoped alternatives.