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.

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.
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.
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:
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:
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:
# Remove zone.js polyfill from angular.json build and test targets
# Then uninstall the package
npm uninstall zone.jsCom 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 viaChangeDetectorRef- Operacoes assincronas marcadas com
AsyncPipeque 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:
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<div class="counter">
<button (click)="decrement()">-</button>
<span>{{ count() }}</span>
<button (click)="increment()">+</button>
<p>Double: {{ doubled() }}</p>
</div>
`
})
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.
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:
@Component({
selector: 'app-user-status',
template: `<span>{{ statusMessage }}</span>`
})
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:
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-user-status',
template: `<span>{{ statusMessage() }}</span>`
})
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():
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: `
<input [formControl]="searchControl" placeholder="Search..." />
<p>Results for: {{ searchTerm() }}</p>
`
})
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.
Pronto para mandar bem nas entrevistas de Angular?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
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:
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()) {
<div>{{ data()!.title }}</div>
} @else {
<div>Loading...</div>
}
`
})
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.
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 utilizaNgZone.run()para forcar atualizacoes deve migrar paraChangeDetectorRef.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, retornatrueconstantemente, 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, 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 aborda vários desses topicos em profundidade, e o modulo 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 oprovideZonelessChangeDetection()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
PendingTaskssubstitui 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
NgZonepermanece 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
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Tags
Compartilhar
Artigos relacionados

Angular Standalone Components: Guia Completo de Migração e Boas Práticas em 2026
Guia completo sobre Angular Standalone Components com migração passo a passo via CLI, roteamento com loadComponent, eliminação de NgModules, testes e ganhos de performance. Exemplos práticos com código.

Angular 18: Signals e Novas Funcionalidades
Angular 18 estabiliza Signals como primitiva reativa, introduz APIs baseadas em signals e habilita deteccao de mudancas sem Zone.js para aplicacoes mais performaticas.

Top 25 Perguntas de Entrevista Angular: Guia Completo para o Sucesso
As 25 perguntas de entrevista Angular mais frequentes em 2026. Respostas detalhadas, exemplos de código e dicas para conquistar a vaga de desenvolvedor Angular.