Without Zone.js, Angular no longer patches every async API (setTimeout, DOM events, promises) to trigger change detection automatically — `provideExperimentalZonelessChangeDetection` removes that global monkey-patching entirely. Change detection is instead scheduled only when a signal read inside a template actually changes value, tracked via the reactive graph that `computed` and `signal` build. Any state mutation that bypasses signals — mutating a plain object property and expecting the view to notice — becomes permanently invisible to the view, since there is no zone left to catch it as a fallback, which is exactly the trade-off expert Angular work needs to reason about explicitly.
import { bootstrapApplication } from '@angular/platform-browser';import { provideExperimentalZonelessChangeDetection } from '@angular/core';import { Component, signal, computed } from '@angular/core';@Component({selector: 'app-price-badge',standalone: true,template: `<span>{{ formatted() }}</span>`,})export class PriceBadgeComponent {private cents = signal(0);formatted = computed(() =>new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(this.cents() / 100),);setCents(value: number): void {this.cents.set(value);}}bootstrapApplication(PriceBadgeComponent, {providers: [provideExperimentalZonelessChangeDetection()],});