# Angular 19 Zoneless: Performance e Change Detection Sem Zone.js em 2026 > Guia completo sobre Angular zoneless change detection: como funciona o provideZonelessChangeDetection, migracao de Zone.js para signals, armadilhas com setTimeout e formularios reativos, SSR sem Zone.js, benchmarks de performance e o roadmap do Angular 19 ao 21. - Published: 2026-04-27 - Updated: 2026-04-27 - Author: SharpSkill - Tags: angular, zoneless, change-detection, performance, signals, zone-js - Reading time: 10 min --- A remocao do Zone.js representa a maior mudanca arquitetural no sistema de change detection do Angular desde a introducao do framework. Desde o Angular 2, o Zone.js atuava como uma camada invisivel que interceptava todas as operacoes assincronas do navegador — de cliques e timers a requisicoes HTTP — para notificar o framework sobre potenciais alteracoes de estado. Embora essa abordagem garantisse que a interface estivesse sempre atualizada, o custo em termos de performance e complexidade de depuracao era significativo. Com o Angular 19 introduzindo `provideExperimentalZonelessChangeDetection` e o Angular 20 estabilizando a API como `provideZonelessChangeDetection`, os desenvolvedores ganham controle total sobre quando e como o Angular detecta mudancas na interface. O modo zoneless substitui o modelo de interceptacao global por um sistema baseado em notificacoes explicitas via Signals. Em vez de executar ciclos de change detection apos cada callback assincrono, o Angular passa a reagir somente quando um signal utilizado em um template e atualizado. O resultado e uma reducao drastica no numero de verificacoes desnecessarias, bundles menores e stack traces limpos sem frames adicionais do Zone.js. > **Cronograma de estabilizacao** > > O Angular 19 disponibiliza o modo zoneless como experimental via `provideExperimentalZonelessChangeDetection()`. No Angular 20, a API e promovida a estavel como `provideZonelessChangeDetection()`. O Angular 21 tera a opcao de gerar novos projetos sem Zone.js por padrao via CLI. ## Como funciona o change detection com Zone.js Para compreender o impacto do modo zoneless, e fundamental entender o papel do Zone.js no modelo tradicional. O Zone.js aplica monkey patches em mais de 130 APIs do navegador — `setTimeout`, `setInterval`, `addEventListener`, `Promise.then`, `XMLHttpRequest`, `fetch` e muitas outras. Cada vez que uma dessas funcoes e executada, o Zone.js intercepta o callback e notifica o Angular de que algo potencialmente mudou no estado da aplicacao. Essa notificacao dispara um ciclo completo de change detection. O Angular percorre toda a arvore de componentes, comparando os valores atuais com os anteriores para identificar o que precisa ser re-renderizado. Em aplicacoes com centenas de componentes, esse processo pode envolver milhares de verificacoes por interacao do usuario, mesmo quando apenas um unico valor foi alterado. ```typescript // app.config.ts - Traditional Zone.js setup (Angular 18-19) import { ApplicationConfig } from '@angular/core'; import { provideZoneChangeDetection } from '@angular/core'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), // Zone.js patches ~130+ browser APIs // Every async callback triggers change detection ] }; ``` A opcao `eventCoalescing: true` mitiga parcialmente o problema ao agrupar multiplos eventos em um unico ciclo de change detection. Porem, o overhead fundamental permanece: o Zone.js adiciona aproximadamente 33 KB ao bundle (10 KB gzipped), insere frames adicionais em todas as stack traces e executa verificacoes globais independentemente de onde a mudanca ocorreu. Em cenarios de alta frequencia — como animacoes, scroll handlers ou inputs de formularios — o modelo Zone.js gera centenas de ciclos de change detection por segundo, muitos deles completamente desnecessarios. Esse e o problema central que o modo zoneless resolve. ## Habilitando o modo zoneless no Angular 19 e 20 A transicao para o modo zoneless envolve duas etapas: substituir o provider de change detection e remover o pacote zone.js do projeto. No Angular 19, a API e marcada como experimental: ```typescript // app.config.ts - Angular 19 (experimental) import { ApplicationConfig } from '@angular/core'; import { provideExperimentalZonelessChangeDetection } from '@angular/core'; export const appConfig: ApplicationConfig = { providers: [ provideExperimentalZonelessChangeDetection(), // No more Zone.js patching ] }; ``` A partir do Angular 20, a API e estabilizada e o prefixo experimental e removido: ```typescript // app.config.ts - Angular 20+ (stable) import { ApplicationConfig } from '@angular/core'; import { provideZonelessChangeDetection } from '@angular/core'; export const appConfig: ApplicationConfig = { providers: [ provideZonelessChangeDetection(), ] }; ``` Apos configurar o provider, o Zone.js deve ser removido do projeto. O polyfill precisa ser excluido tanto dos targets de build quanto de teste no `angular.json`, e o pacote desinstalado: ```bash # Remove zone.js polyfill from angular.json build and test targets # Then uninstall the package npm uninstall zone.js ``` Com essas alteracoes, o Angular deixa de interceptar operacoes assincronas e passa a depender exclusivamente de notificacoes explicitas para disparar atualizacoes na interface. ## O que dispara o change detection no modo zoneless Sem o Zone.js interceptando callbacks assincronos, o Angular precisa de mecanismos explicitos para saber quando atualizar a interface. No modo zoneless, os seguintes eventos disparam change detection: - **Atualizacoes de signals** utilizados em templates - **Eventos do template** (click, input, submit) via event bindings do Angular - **`markForCheck()`** chamado explicitamente via `ChangeDetectorRef` - **Operacoes assincronas marcadas com `AsyncPipe`** que emitem novos valores - **`ChangeDetectorRef.detectChanges()`** para forcamento local O mecanismo principal e o sistema de Signals. Quando um signal referenciado em um template e atualizado, o Angular identifica exatamente quais componentes precisam ser re-renderizados, sem percorrer a arvore inteira: ```typescript // counter.component.ts - Signal-driven change detection import { Component, signal, computed } from '@angular/core'; @Component({ selector: 'app-counter', template: `
{{ count() }}

Double: {{ doubled() }}

` }) export class CounterComponent { // Signal updates automatically notify the template count = signal(0); doubled = computed(() => this.count() * 2); increment() { this.count.update(v => v + 1); // No markForCheck() needed - signal handles notification } decrement() { this.count.update(v => v - 1); } } ``` Nesse exemplo, ao clicar no botao, o evento de click dispara a funcao `increment()`, que atualiza o signal `count`. O Angular detecta automaticamente que o template referencia `count()` e `doubled()`, re-renderizando apenas as partes afetadas. Nao ha varredura global na arvore de componentes — a atualizacao e precisa e cirurgica. > **OnPush e modo zoneless** > > Componentes com `changeDetection: ChangeDetectionStrategy.OnPush` ja operam de forma semelhante ao modelo zoneless, reagindo apenas a mudancas em inputs e chamadas explicitas de `markForCheck()`. No modo zoneless, o `OnPush` continua funcional, mas os Signals oferecem uma abordagem mais ergonomica e performatica por eliminarem a necessidade de `markForCheck()` manual. ## Armadilhas da migracao: setTimeout, formularios reativos e padroes legados A principal fonte de problemas na migracao para o modo zoneless sao componentes que dependem implicitamente do Zone.js para disparar atualizacoes na interface. O padrao mais comum envolve o uso de `setTimeout` ou `setInterval` com atribuicoes diretas a propriedades do componente. No modelo com Zone.js, o seguinte codigo funciona corretamente porque o Zone.js intercepta o callback do `setTimeout` e dispara change detection: ```typescript // user-status.component.ts - Before: relies on Zone.js @Component({ selector: 'app-user-status', template: `{{ statusMessage }}` }) export class UserStatusComponent { statusMessage = 'Loading...'; ngOnInit() { setTimeout(() => { // Zone.js would trigger CD here - zoneless does NOT this.statusMessage = 'Ready'; }, 2000); } } ``` No modo zoneless, esse componente permanece exibindo "Loading..." indefinidamente. O `setTimeout` executa normalmente, a propriedade `statusMessage` e atualizada em memoria, mas o Angular nao recebe nenhuma notificacao sobre a mudanca. A solucao e migrar para signals: ```typescript // user-status.component.ts - After: signal-based approach import { Component, signal } from '@angular/core'; @Component({ selector: 'app-user-status', template: `{{ statusMessage() }}` }) export class UserStatusComponent { statusMessage = signal('Loading...'); ngOnInit() { setTimeout(() => { // Signal update notifies Angular automatically this.statusMessage.set('Ready'); }, 2000); } } ``` A chamada `this.statusMessage.set('Ready')` notifica o Angular de que o valor mudou, disparando a atualizacao do template mesmo dentro de um callback de `setTimeout`. Outro cenario frequente envolve formularios reativos. O `FormControl` do Angular emite valores via observables, que no modelo Zone.js disparam change detection automaticamente. No modo zoneless, a atualizacao da interface depende da conversao do observable para signal utilizando `toSignal()`: ```typescript // search.component.ts - Reactive forms with zoneless import { Component, inject, signal } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { toSignal } from '@angular/core/rxjs-interop'; import { debounceTime, distinctUntilChanged } from 'rxjs'; @Component({ selector: 'app-search', imports: [ReactiveFormsModule], template: `

Results for: {{ searchTerm() }}

` }) export class SearchComponent { searchControl = new FormControl(''); // Convert observable to signal for automatic template updates searchTerm = toSignal( this.searchControl.valueChanges.pipe( debounceTime(300), distinctUntilChanged() ), { initialValue: '' } ); } ``` A funcao `toSignal()` do pacote `@angular/core/rxjs-interop` converte qualquer observable em um signal, criando a ponte entre o mundo reativo do RxJS e o sistema de notificacoes do modo zoneless. Essa abordagem e especialmente relevante para formularios complexos que utilizam operadores como `debounceTime` e `distinctUntilChanged`. ## SSR sem Zone.js: PendingTasks e estabilizacao O Server-Side Rendering apresenta um desafio adicional no modo zoneless. Com o Zone.js, o Angular detectava automaticamente quando todas as operacoes assincronas haviam sido concluidas para serializar o HTML e envia-lo ao cliente. Sem o Zone.js, essa deteccao automatica deixa de existir. O Angular resolve esse problema com a API `PendingTasks`. Essa classe permite registrar tarefas assincronas que devem ser concluidas antes da serializacao do SSR. O metodo `run()` aceita uma funcao assincrona e impede a serializacao ate que a Promise retornada seja resolvida: ```typescript // data-loader.component.ts - SSR-compatible async loading import { Component, inject, signal } from '@angular/core'; import { PendingTasks } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { firstValueFrom } from 'rxjs'; @Component({ selector: 'app-data-loader', template: ` @if (data()) {
{{ data()!.title }}
} @else {
Loading...
} ` }) export class DataLoaderComponent { private http = inject(HttpClient); private pendingTasks = inject(PendingTasks); data = signal<{ title: string } | null>(null); ngOnInit() { // PendingTasks.run() prevents SSR serialization until complete this.pendingTasks.run(async () => { const result = await firstValueFrom( this.http.get<{ title: string }>('/api/data') ); this.data.set(result); }); } } ``` Sem o `PendingTasks.run()`, o servidor serializaria o HTML antes do carregamento dos dados, resultando em um flash de "Loading..." que seria substituido pelo conteudo real apos a hidratacao no cliente. Com o `PendingTasks`, o servidor aguarda a conclusao da requisicao HTTP e serializa o HTML com os dados ja preenchidos, proporcionando uma experiencia de carregamento suave e otimizada para SEO. Para aplicacoes que utilizam o `HttpClient` do Angular, as requisicoes feitas durante o SSR ja sao rastreadas automaticamente quando se utiliza `provideClientHydration()`. O `PendingTasks` e necessario para operacoes assincronas customizadas que nao passam pelo `HttpClient`. ## Benchmarks de performance: Zone.js vs Zoneless Os ganhos de performance do modo zoneless sao mensuráveis em múltiplas dimensoes. A tabela a seguir apresenta dados comparativos entre uma aplicacao Angular de medio porte operando com Zone.js e a mesma aplicacao migrada para o modo zoneless: | Metrica | Zone.js | Zoneless | Melhoria | |---------|---------|----------|----------| | Tamanho do bundle inicial | +33KB bruto / +10KB gzip | 0KB de overhead | 100% de reducao | | Ciclos de change detection (app tipica) | 150-300 por interacao | 5-15 por interacao | 80-95% menos | | Profundidade da stack trace | 8-12 frames extras do Zone | Traces nativos limpos | Clareza imediata | | Time to Interactive (TTI) | Baseline | 15-25% mais rapido | Bootstrap do Zone eliminado | A reducao de 80-95% nos ciclos de change detection e o ganho mais impactante para a experiencia do usuario. Em uma aplicacao com formularios complexos e atualizacoes frequentes, o modelo Zone.js dispara centenas de verificacoes por segundo, enquanto o modo zoneless reage apenas as mudancas efetivas nos signals referenciados pelos templates. A eliminacao dos frames do Zone.js nas stack traces e um beneficio significativo para a produtividade dos desenvolvedores. No modelo tradicional, cada erro apresenta 8 a 12 frames adicionais do Zone.js que obscurecem a origem real do problema. No modo zoneless, as stack traces sao limpas e apontam diretamente para o codigo da aplicacao. > **Compatibilidade com bibliotecas de terceiros** > > Algumas bibliotecas de terceiros dependem do Zone.js para disparar atualizacoes na interface. Antes de migrar para o modo zoneless, e recomendavel verificar a compatibilidade das dependencias do projeto. Bibliotecas que utilizam `NgZone.run()` ou dependem implicitamente da interceptacao do Zone.js podem exigir adaptacoes. O Angular Material e o CDK ja sao totalmente compativeis com o modo zoneless desde a versao 19. ## APIs do NgZone que sobrevivem ao modo zoneless Mesmo com a remocao do Zone.js, a classe `NgZone` continua disponivel no Angular. No modo zoneless, o `NgZone` opera como um no-op — suas funcoes existem mas nao executam nenhuma logica de zona. Essa decisao de design garante retrocompatibilidade com codigo que referencia o `NgZone` diretamente. As APIs relevantes incluem: - **`NgZone.run()`**: No modo zoneless, executa o callback diretamente sem nenhum wrapper de zona. Codigo existente que utiliza `NgZone.run()` para forcar atualizacoes deve migrar para `ChangeDetectorRef.detectChanges()` ou, preferencialmente, para signals. - **`NgZone.runOutsideAngular()`**: No modelo Zone.js, essa funcao era usada para executar operacoes de alta frequencia (animacoes, scroll handlers) sem disparar change detection. No modo zoneless, essa funcao e desnecessaria, pois operacoes assincronas ja nao disparam change detection automaticamente. - **`NgZone.isStable`**: No modo zoneless, retorna `true` constantemente, pois nao ha tarefas de zona para rastrear. A presenca dessas APIs como no-ops permite que bibliotecas que referenciam o `NgZone` continuem funcionando sem alteracoes imediatas, facilitando a transicao gradual do ecossistema. ## Roadmap do Angular 19 ao 21: cronograma de estabilizacao A remocao do Zone.js e um processo gradual que se estende por tres versoes principais do Angular: - **Angular 19 (atual)**: O `provideExperimentalZonelessChangeDetection()` esta disponivel para adocao antecipada. O Zone.js permanece como padrao para novos projetos. Todas as APIs de signals estao estaveis. - **Angular 20**: A API e promovida a estavel como `provideZonelessChangeDetection()`. O prefixo experimental e removido. Novos projetos gerados pelo CLI continuam com Zone.js por padrao, mas a migracao e oficialmente recomendada. - **Angular 21**: O CLI oferecera a opcao de gerar projetos sem Zone.js por padrao. A documentacao oficial priorizara exemplos sem Zone.js. O Zone.js sera depreciado mas continuara funcional para projetos legados. Esse cronograma gradual permite que o ecossistema — bibliotecas de terceiros, ferramentas de teste e projetos corporativos — se adapte progressivamente. A equipe do Angular tem mantido retrocompatibilidade total em cada etapa, garantindo que projetos existentes continuem funcionando sem alteracoes durante a transicao. Para desenvolvedores que se preparam para [perguntas de entrevista Angular](/technologies/angular/interview-questions/change-detection), o entendimento do modo zoneless e agora essencial. Questoes sobre change detection, signals e otimizacao de performance aparecem com frequencia crescente em processos seletivos. O artigo sobre as [top 25 perguntas de entrevista Angular](/blog/angular/top-25-angular-interview-questions) aborda vários desses topicos em profundidade, e o [modulo Angular Signals](/technologies/angular/interview-questions/angular-signals) oferece exercicios praticos sobre o sistema reativo que fundamenta o modo zoneless. ## Conclusao O modo zoneless representa uma evolucao fundamental na arquitetura do Angular, substituindo a interceptacao global do Zone.js por um sistema de notificacoes granulares baseado em Signals. Os principais pontos abordados neste guia incluem: - O Zone.js intercepta mais de 130 APIs do navegador e dispara ciclos globais de change detection apos cada operacao assincrona, gerando overhead significativo em aplicacoes de medio e grande porte - O `provideExperimentalZonelessChangeDetection()` no Angular 19 e o `provideZonelessChangeDetection()` no Angular 20+ habilitam o modo zoneless, eliminando completamente o Zone.js do bundle - Signals sao o mecanismo principal de notificacao no modo zoneless — atualizacoes em signals referenciados por templates disparam re-renderizacao precisa sem varredura global - Codigo que depende do Zone.js implicitamente (setTimeout com atribuicoes diretas, formularios reativos sem `toSignal()`) deve ser migrado para signals para funcionar corretamente - O `PendingTasks` substitui a deteccao automatica do Zone.js no SSR, permitindo controle explicito sobre a estabilizacao antes da serializacao - Benchmarks demonstram reducoes de 80-95% nos ciclos de change detection e eliminacao de 33 KB do bundle inicial - O `NgZone` permanece disponivel como no-op para retrocompatibilidade, facilitando a migracao gradual de bibliotecas e projetos existentes - O roadmap do Angular 19 ao 21 estabelece um caminho claro de estabilizacao, com o Zone.js sendo depreciado gradualmente ate a geracao de projetos zoneless por padrao --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/angular/angular-19-zoneless-change-detection-performance