Ch. 4 · Angular

Angular Zoneless Change Detection

Run Angular without zone.js, drive updates with signals, and understand which async sources still schedule change detection.

~2 min readadvancedupdated Oct 5, 2026

Historically Angular used zone.js to patch async APIs and trigger change detection after every asynchronous task. Zoneless mode removes that patch: change detection runs when a signal changes or when you explicitly notify Angular, which cuts overhead and bundle size.

Before you start

You should be comfortable with change detection and signals. This article assumes a recent Angular version that supports zoneless change detection.

Step-by-step walkthrough

Step 1: Enable zoneless and drop zone.js

Provide zoneless change detection in the bootstrap so Angular no longer depends on zone.js, and remove zone.js from the polyfills. The build gets smaller, and updates are driven by signal writes rather than by patched async events.

Step 2: Drive updates with signals

A signal write notifies Angular to check the components that read it, so count.set(count() + 1) schedules an update. Values that are not signals do not schedule anything, so state that should update the view needs to be a signal or you must notify Angular explicitly.

Step 3: Notify Angular for external async sources

For callbacks from libraries that do not use signals, such as a chart’s event or a raw setTimeout, inject ApplicationRef or ChangeDetectorRef and call markForCheck after updating state. This is the replacement for the automatic notification zone.js used to provide.

Worked scenario

The component updates from a plain timer and tells Angular to check.

import { Component, inject, signal, ApplicationRef } from '@angular/core';

@Component({ selector: 'app-clock', template: '{{ ticks() }}', standalone: true })
export class ClockComponent {
  private appRef = inject(ApplicationRef);
  ticks = signal(0);

  constructor() {
    setInterval(() => {
      this.ticks.update((n) => n + 1);
      this.appRef.tick();
    }, 1000);
  }
}
TypeScript

Walk through the example

The signal write marks the component dirty, and appRef.tick() runs change detection for the scheduled work because the interval is not a source Angular tracks. In many cases the signal update alone is enough; the explicit tick covers the non-signal async source, which is precisely the gap zoneless mode leaves.

Common mistake

Removing zone.js but keeping plain mutable fields, so updates never reach the view until something else triggers a check. Another is calling tick() on every event, which re-checks the whole app; prefer signals so only affected components update.

Verify the behavior

Toggle a signal value and confirm the view updates without zone.js. Use a non-signal async callback and confirm the view updates only after markForCheck or tick. Remove zone.js from the polyfills and confirm the build still runs.

Interview exercise

What replaces zone.js as the trigger for change detection in a zoneless app?

Answer and reasoning

Signal writes are the primary trigger: Angular schedules a check for the components that depend on the changed signal. For async sources that are not signals, you notify Angular explicitly with markForCheck or tick. Together they cover the cases zone.js used to handle automatically, but with far less patching and overhead.

Continue learning

Compare update triggers in OnPush and input identity and signal effect scope. Read the Angular zoneless guide and try the Angular interview questions.

More in Angular

read ✓Angular · hard

Angular Resource API for Async Data

Load data reactively with the resource API, track loading and error state as signals, and cancel stale requests automatically.

~2 min readread →
read ✓Angular · hard

Angular Signal Forms Overview

Model forms as signals, bind fields in the template, and reason about validation and derived state in a signal-driven form.

~2 min readread →
read ✓Angular · mid

Angular Defer Blocks and Lazy Rendering

Load template regions on demand with @defer, choose a trigger, and use placeholders without delaying critical content.

~2 min readread →
esc