---
title: "A Small Checklist Before Trying Zoneless"
description: "A readiness checklist for testing zoneless Angular in an existing app without confusing a compatibility spike with a rollout."
deck: "Zoneless is not just deleting zone.js. In an existing app, the real work is finding who tells Angular that state changed. [Stable since v20.2 and default in new projects from v21](https://angular.dev/guide/zoneless); for an existing app, the spike is a different conversation."
author: "André Ramos"
url: "https://andreramos.dev/angular/zoneless-checklist/"
lang: "en"
type: "article"
---

# A Small Checklist Before Trying Zoneless

> Zoneless is not just deleting zone.js. In an existing app, the real work is finding who tells Angular that state changed. [Stable since v20.2 and default in new projects from v21](https://angular.dev/guide/zoneless); for an existing app, the spike is a different conversation.

## Start with a branch, not a promise

Zoneless is the Angular direction for new applications, but an existing app may depend on Zone.js through patterns that were never written down. Treat the first attempt as a compatibility spike.

The first spike is not a migration sprint. It is a way to find the screens where a timer, subscription, overlay, or third-party widget has been leaning on implicit change detection for years.

## What to inspect

| Area | Question |
|---|---|
| Manual subscriptions | Does the code update plain fields without a Signal, AsyncPipe, input change, or markForCheck? |
| Timers | Do setTimeout or setInterval callbacks change data that the template reads without notifying Angular? |
| Stability APIs | Does code wait on NgZone stability events or treat isStable as a runtime gate? |
| Forms | Do reactive forms and validation states update correctly in critical flows? |
| Third-party UI | Do overlays, charts, editors, and maps assume Zone.js? |
| Tests | Does the test setup still import zone.js/testing? |

*Find likely zoneless risk points*

```bash
rg "NgZone|onStable|onUnstable|onMicrotaskEmpty|isStable|ApplicationRef|setTimeout|setInterval|subscribe\(" src
rg "zone.js|zone.js/testing|provideZoneChangeDetection|provideZonelessChangeDetection" .
```

## A good spike output

A good zoneless spike ends with a short report: flows tested, failures found, dependencies that assume Zone.js, changes required, and a recommendation to adopt, test more, or wait.

A useful report is specific: checkout passed, the chart overlay failed after a timer mutation, the editor package still assumes Zone.js, and the estimated fix is either two components or a dependency upgrade.

If the only output is 'it compiled', the spike did not answer the production question. A production team needs to know what broke, what was untouched, and what would be expensive to fix.

## Reusable artifact: Zoneless readiness checklist

- Create an isolated branch.
- Remove Zone.js assumptions only inside the spike.
- Test manual subscriptions, timers, stability APIs, forms, overlays, charts, editors, and maps.
- Check build and test polyfills.
- Write a recommendation before planning rollout.

## Sources checked

- https://angular.dev/guide/zoneless
- https://angular.dev/api/core/provideZonelessChangeDetection
- https://angular.dev/api/core/ChangeDetectorRef
- https://angular.dev/api/core/ChangeDetectionStrategy
- https://angular.dev/api/core/rxjs-interop/takeUntilDestroyed
- https://angular.dev/best-practices/zone-pollution
- https://blog.angular.dev/announcing-angular-v20-b5c9c06cf301
- https://blog.angular.dev/announcing-angular-v21-57946c34f14b
- https://github.com/angular/angular/discussions/66779

## Related

- [The Code That Breaks When Angular Goes Zoneless](https://andreramos.dev/angular/code-that-breaks-when-angular-goes-zoneless/)
- [NG0100 ExpressionChangedAfterItHasBeenCheckedError: Why It Surfaces in Zoneless Angular](https://andreramos.dev/angular/expressionchanged-error-zoneless-angular/)
- [OnPush Is the Default in Angular 22: What Breaks and What to Do](https://andreramos.dev/angular/onpush-default-angular-22/)
