With the release of Angular version 18 on 22 may 2024, the framework introduces an exciting experimental feature: zoneless Angular apps. This innovation eliminates the reliance on the Zone.js library, offering improved performance, reduced overhead, and a simplified debugging experience. In this article, we’ll explore what zoneless applications entail, the advantages they offer, and how you can experiment with this cutting-edge functionality.

Understanding Change Detection in Angular (Pre-Zoneless)

Change detection ensures that the application's DOM stays in sync with the underlying data model in components. Traditionally, Angular has relied on Zone.js to manage change detection. Here's a quick overview of when change detection occurs:

  • User Interactions: Events like button clicks or typing in an input field.
  • Asynchronous Operations: Actions such as HTTP requests, setTimeout, setInterval or Promise resolutions.
  • Manual Triggers: Invocations like ApplicationRef.tick() or ChangeDetectorRef.detectChanges().

Zone.js achieves this by patching browser APIs (e.g., events or timers) and notifying Angular to start change detection. While this approach works seamlessly, it introduces some overhead and can lead to issues like the infamous ExpressionChangedAfterItHasBeenCheckedError.

Examples of Change Detection Before Zoneless

Before Angular introduced zoneless change detection, Zone.js was central to automatically tracking and propagating changes to the UI. The following embedded StackBlitz example demonstrates various scenarios:

  1. Simple property set in an event handler: Clicking a button updates a counter property. Zone.js intercepts the event, schedules a change detection cycle, and the UI reflects the updated value.
  2. Simple property set asynchronously: An interval updates a tick property every second. Zone.js detects the asynchronous operation (setInterval) and schedules change detection to reflect the updated value in the DOM.
  3. Data retrieved from HTTP and stored in an array: Data fetched via an HTTP request is stored in an array, and Angular’s default change detection ensures the view updates automatically without requiring user interaction. This works because HttpClient operates within Angular's zone, triggering change detection when the response is received. However, if the component uses ChangeDetectionStrategy.OnPush and the array is mutated directly (e.g., using push), the view might not update unless the reference changes or change detection is triggered manually.
  4. Data retrieved from HTTP with async pipe: Using the AsyncPipe simplifies observables by automatically subscribing and triggering change detection when new data is emitted, eliminating manual handling.
  5. Data retrieved from HTTP and stored in a signal: With signals, introduced in modern Angular, state changes directly notify dependent readers, streamlining updates and making the process independent of Zone.js.

These examples showcase how Zone.js historically handled asynchronous operations and change detection, paving the way for Angular's more efficient, lightweight, and scalable zoneless architecture.

Why Go Zoneless?

Moving away from Zone.js brings several benefits:

  • Simplified Change Detection: Developers no longer need to contend with ExpressionChangedAfterItHasBeenCheckedError and other zone-related quirks.
  • Reduced Overhead: Eliminating zone.js lightens the framework, improving runtime performance.
  • Improved Debugging: Zoneless applications provide better control over change detection, making it easier to pinpoint performance bottlenecks.

How to Configure a Zoneless Angular Application?

Switching to a zoneless application requires a few configuration changes. Here's a step-by-step guide:

  1. Enable Experimental Zoneless Change Detection In app.config.ts, add the following provider:
providers: [
  provideExperimentalZonelessChangeDetection()
]

Ensure you remove the provideZoneChangeDetection() provider if it exists.

  1. Remove zone.js Imports
  • Delete import 'zone.js'; from your application files.
  • Update angular.json to remove zone.js from the polyfills section:
"polyfills": []
  1. Uninstall zone.js Run the following command to remove zone.js from your project:
npm uninstall zone.js

Testing Change Detection Without Zone.js

The following example demonstrates how change detection behaves in various scenarios without the use of zone.js.

In this example, we’ve kept the initial setup and simply removed Zone.js. Now, let's break down each of the five scenarios mentioned in the example, analyzing them case by case without Zone.js:

First Case: Simple Property Set in an Event Handler


As you can observe, it works as before, and the view updates when the "increment" button is clicked.

Second Case: Simple Property Set Asynchronously

Here’s the example:

Without Zone.js, asynchronous changes like setInterval don’t automatically update the UI, we can fix this by calling:

this.changeDetectorRef.markForCheck();

Here’s the corrected version:

Alternatively, we can use signals for a cleaner solution:

Here’s the updated version:

In Summary:

  • Use tick = signal(0); instead of tick = 0;.
  • Replace this.tick += 1; with this.tick.update((value) => value + 1);.
  • Call tick() in the HTML instead of directly using tick.

Third Case: Data Retrieved from HTTP and stored in an Array

In this example, you’ll notice that the view is not updated:

To fix this, we can again use:

this.changeDetectorRef.markForCheck();

Here’s the corrected version:

But rather than relying on ChangeDetectorRef, I prefer using async, which automatically updates the view. This leads us to the fourth use case.

Fourth Case: Data Retrieved from HTTP with Async Pipe

This is straightforward, just apply the async pipe in the HTML as shown in the following example:


There’s also a third approach: using signals, similar to what we did in the second case for handling asynchronous scenarios. Here’s how in the following section ...

Fifth Case: Data Retrieved from HTTP and Stored in a Signal

  • Instead of: users$ = this.getData(); use: usersSignal = toSignal(this.getData(), { initialValue: [] });
  • And in the template, replace: @for(user of users$ | async; track user.id) with: @for(user of usersSignal(); track user.id)


In conclusion:

  • Property Updates in Events
    When a property is updated within an event handler (e.g., button click), the UI updates seamlessly, just as before.
  • Asynchronous Operations
    Updating properties asynchronously (e.g., setInterval) requires manual intervention. Without zone.js, Angular is unaware of state changes. You can address this by explicitly calling:
this.changeDetectorRef.markForCheck();

This schedules a manual change detection cycle, ensuring the UI updates.

  • HTTP Requests with Observables When retrieving data via HTTP and storing it in an array, the UI doesn't update automatically. Use the async pipe in your templates to handle this gracefully:
<div *ngFor="let user of users$ | async">
  {{ user.name }}
</div>

The async pipe subscribes to the observable, triggering change detection whenever new data is emitted.

  1. Signals for Change Detection
    Angular’s experimental signals offer a powerful alternative. By converting state to signals, Angular registers them as view dependencies. When the signal updates, the UI automatically reflects the changes without manual triggers:
  2. HTTP Requests with Signals
    Convert observables to signals using toSignal():
    Angular manages subscriptions automatically, and the UI updates whenever the signal changes.
On November 19, 2025, with the release of Angular 19, the framework advanced its efforts to enhance and refine zoneless application support. Six months after the initial experimental release, the Angular team has enhanced APIs, introduced support for server-side rendering, and improved the testing experience. While there are still some refinements before the API reaches developer preview, Angular remains committed to iterating on this feature in 2025. Developers are encouraged to explore zoneless in their projects using the Angular CLI:
ng new [project-name] --experimental-zoneless  

Author Of article : Houdass Youness Read full article