Architecture
Angular Zoneless Change Detection: A Practical Migration Guide
Going zoneless is the final step, not the first. Make Angular state changes explicit, fix async boundaries and migrate incrementally before removing Zone.js.

Enabling zoneless change detection is one of the smallest parts of a zoneless Angular migration. The difficult part is finding the places where the application currently depends on Zone.js to notice that something changed.
The migration becomes much safer when zoneless is treated as a property the application earns rather than a flag that gets enabled first.
Why a big-bang Angular zoneless migration is risky

A long-lived migration branch quickly diverges from active feature development. Every feature merged into main creates another conflict with code that may already have been converted on the migration branch.
A safer approach is to make each preparation step independently useful and merge it directly into the application while Zone.js is still present.
Step 1: audit your Angular Zone.js dependencies
rg -n "setTimeout|setInterval" src --type ts rg -n "NgZone|runOutsideAngular|ApplicationRef.tick" src --type ts rg -n "detectChanges|markForCheck|ChangeDetectorRef" src --type ts rg -n "addEventListener|new Worker|WebSocket|IntersectionObserver" src --type tsClassify the results instead of automatically replacing them. Some are state mutations that should become explicit signal writes. Some are legitimate work outside Angular. Others are manual change-detection calls that reveal an existing notification problem.
Step 2: convert change-detection triggers to Signals
The useful migration boundary is the source of the asynchronous state change rather than the component consuming it. Once a timer or callback writes to a signal, every consumer of that signal has an explicit notification mechanism.
export class SessionBannerComponent {
readonly remaining = signal(0);
private readonly session = inject(SessionService);
constructor() {
const id = setInterval(() => {
this.remaining.set( this.session.secondsLeft() );
}, 1000);
inject(DestroyRef).onDestroy(() => {
clearInterval(id);
});
}
}Step 3: handle the Angular RxJS boundary correctly

Zoneless Angular does not mean removing RxJS. Search debouncing, cancellation, WebSockets and merged asynchronous sources are still stream problems.
The important distinction is the boundary where an observable result becomes component state. Converting that boundary to a signal makes the notification explicit.
export class CaseListComponent {
private readonly api = inject(CaseApi);
readonly cases = toSignal( this.api.cases(), {
initialValue: [] as Case[],
} );
}Step 4: audit third-party Angular libraries
Third-party libraries often determine the real migration timeline. Charting libraries, map SDKs, older UI components and browser integrations may invoke callbacks outside Angular.
At those boundaries, update application state explicitly rather than depending on the zone to observe the callback.
export class ChartHostComponent {
readonly selectedPoint = signal<Point | null>(null);
private init(el: HTMLElement): void {
thirdPartyChart(el, {
onSelect: (point: Point) => {
this.selectedPoint.set(point);
},
});
}
}Step 5: enable Angular zoneless change detection

Once application state changes are explicit and third-party boundaries have been audited, enabling zoneless change detection becomes the final verification step rather than the beginning of the migration.
bootstrapApplication(AppComponent, {
providers: [ provideZonelessChangeDetection(), provideBrowserGlobalErrorListeners(), ],
});Remove Zone.js from both application and test polyfills. Keeping it in the test environment can hide exactly the notification problems the migration is intended to expose.
The real benefit of zoneless Angular
The strongest reason to migrate is not a single benchmark. Zoneless architecture encourages precise state ownership and explicit notification boundaries.
Most of that architectural value appears before Zone.js is removed. If each migration step improves the running application independently, the project remains safe to pause, ship and continue without a branch that becomes increasingly difficult to merge.
Keep reading
ArchitectureAngular Signal Forms: Building Custom Controls the Modern Way
Connect custom inputs, toggles, phone fields and rating controls to Angular Signal Forms with reusable validation schemas and clear ownership of form state.
ArchitectureI Stopped Writing Angular the Old Way: 10 Modern Angular Patterns I Use in 2026
The modern Angular patterns I use in 2026, why I use them, and when I would choose something else. A practical guide to clearer state, dependencies, forms, rendering and feature architecture.
