Se você acompanha a evolução do framework do Google nos últimos anos, sabe que ele vem passando por uma reconstrução silenciosa — peça por peça. Com o lançamento do Angular 22 em 3 de junho de 2026, essa reconstrução deixou de ser uma promessa e virou padrão. Não estamos olhando para mais uma leva de features experimentais: estamos olhando para a consolidação de um ecossistema inteiramente repensado.
Para quem vive de aplicações enterprise, Clean Architecture e ecossistemas de Microfrontends, essa é a versão que finalmente entrega o que vinha sendo prometido desde o Angular 16: um framework reativo de ponta a ponta, zone-less por natureza, e com muito menos cerimônia no caminho.
Os experimentos acabaram. A seguir, o que mudou de verdade — e o que você precisa fazer antes de rodar o ng update.
📖 Se você está começando: vários termos técnicos deste artigo (change detection, Signals, SSR, injeção de dependência, microfrontends…) estão explicados num glossário no final. Leia o artigo de ponta a ponta e use o glossário como consulta sempre que bater uma dúvida.
O que chegou estável no Angular 22
-
OnPushé o novo padrão de change detection (o antigoDefaultvirouEagere está depreciado). -
Resource API estável:
resource,rxResourceehttpResourceprontos para produção. - Signal Forms estável, com Submission API, schemas dinâmicos (Zod/Valibot) e interop com Reactive Forms.
-
Novo decorator
@Service(), encurtando o@Injectable({ providedIn: 'root' }). -
injectAsyncpara injeção de dependência lazy, com prefetch viaonIdle. -
debouncedpara debounce nativo em Signals/Resources. - Incremental Hydration ligada por padrão.
-
HttpClientusaFetchBackendpor padrão (withFetch()depreciado). - Melhorias importantes de Router e bootstrap pensadas para Microfrontends.
1. OnPush como novo padrão de Change Detection
Chegou o momento que a comunidade pedia desde sempre: o ChangeDetectionStrategy.OnPush agora é o comportamento padrão de qualquer componente novo. A decisão faz todo sentido num mundo signals-first — quem usa Signals já recebe notificações cirúrgicas sobre o que mudou, e o OnPush aproveita isso ao máximo, verificando apenas os componentes realmente afetados em vez de varrer a árvore inteira.
O antigo Default (que checava a árvore toda) foi renomeado para Eager e está depreciado. Se você ainda precisa do comportamento antigo em algum componente, declare explicitamente:
import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
selector: 'app-legacy',
changeDetection: ChangeDetectionStrategy.Eager, // substitui o antigo 'Default'
template: `...`,
})
export class LegacyComponent {}
Detalhe crítico para a migração: durante o ng update, se o Angular não encontrar uma estratégia explícita, ele aplica Eager automaticamente para não quebrar nada. Ou seja, você não ganha performance "de graça" — precisa migrar componente a componente para colher o benefício do OnPush.
2. Resource API e httpResource estáveis
A Resource API era a peça que faltava no quebra-cabeça dos Signals: derivar dados assíncronos de forma reativa, normalmente disparando requisições HTTP quando um Signal muda. Agora resource, rxResource e httpResource estão estáveis e liberados para produção.
O ponto de entrada mais confortável é o httpResource. Ele recebe uma lambda reativa que retorna a requisição: se um Signal usado lá dentro muda, a requisição é refeita automaticamente.
import { httpResource } from '@angular/common/http';
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { Flight } from './flight';
@Component({
selector: 'app-flight-search',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@if (flightsResource.isLoading()) {
<div>Carregando…</div>
} @else if (flightsResource.error()) {
<div>Erro: {{ flightsResource.error() }}</div>
} @else {
@for (flight of flightsResource.value(); track flight.id) {
<app-flight-card [item]="flight" />
}
}
`,
})
export class FlightSearch {
protected readonly filter = signal({ from: 'São Paulo', to: 'Uberlândia' });
protected readonly flightsResource = httpResource<Flight[]>(
() => ({
url: 'https://api.exemplo.io/flight',
params: { from: this.filter().from, to: this.filter().to },
}),
{ defaultValue: [] }, // evita o componente lidar com `undefined` na inicialização
);
protected reload(): void {
this.flightsResource.reload();
}
}
O recurso gerencia o próprio estado via Signals: value, error, isLoading e um status mais detalhado (idle, loading, reloading, error, resolved, local). E o melhor: race conditions são tratadas automaticamente — se várias requisições chegam em sequência, só o resultado da mais recente é usado, exatamente como o switchMap faria no RxJS, mas sem você escrever uma linha de pipe.
Quer pular a requisição sob certas condições? Basta retornar undefined na lambda.
3. Signal Forms prontos para produção
Acabou a eterna divisão entre Reactive Forms e Template-Driven. Os Signal Forms saíram do status experimental e são a abordagem recomendada para formulários: declarativos, fortemente tipados e reativos por Signals.
O coração da API é a função form, que recebe um Signal com os dados e um schema de validação:
import { form, minLength, required } from '@angular/forms/signals';
protected readonly flightForm = form(this.flight, (path) => {
required(path.from);
required(path.to);
required(path.date);
minLength(path.from, 3);
});
O resultado é um FieldTree: uma estrutura aninhada de Signals em que cada campo expõe value, dirty, invalid e errors. No template, você usa a diretiva FormField:
<input [formField]="flightForm.from" id="flight-from" />
<div>{{ flightForm.from().errors() | json }}</div>
E não para aí. O Angular 22 (somando a 21.1 e 21.2) trouxe um stack de formulários surpreendentemente completo:
-
Submission API (
FormRoot+submit): toda a lógica de envio dentro do próprioform, inclusive recebendo erros de validação do servidor de volta para o estado do formulário. -
Schemas dinâmicos com
validateStandardSchema, compatível com Zod e Valibot — e que reavaliam quando um Signal muda. -
Classes CSS condicionais (
ng-valid,ng-invalid,ng-dirty…) viaprovideSignalFormsConfig. -
Interop com Reactive Forms via
compatFormeSignalFormControl, então você migra de forma incremental sem reescrever o mundo.
4. O novo decorator @Service()
Uma daquelas melhorias de ergonomia que você agradece todo dia. O @Service() encurta o caso mais comum de injeção — aquele @Injectable({ providedIn: 'root' }) repetido à exaustão:
import { Service } from '@angular/core';
@Service()
export class FlightClient {
// Provido em root por padrão. A intenção fica explícita.
}
Se você não quer o provimento automático em root, desligue com autoProvided: false e proveja manualmente (em app.config.ts, no componente ou na rota):
@Service({ autoProvided: false })
export class TabRegistry {}
Importante: o @Service() não aposenta o @Injectable(). Ele é um atalho para o caso mais frequente. Onde você usa configurações de provider mais sofisticadas, o @Injectable() continua sendo a ferramenta certa. Numa Clean Architecture, o @Service() deixa a camada de adaptadores de infraestrutura bem mais enxuta — mas use com critério, não como substituto cego.
5. injectAsync: injeção de dependência lazy
Esse é um presente para quem briga com tamanho de bundle e tempo de startup. Com injectAsync, você injeta uma dependência só quando ela é realmente necessária — ideal para serviços que carregam bibliotecas pesadas e só entram em cena após uma ação específica do usuário:
import { injectAsync } from '@angular/core';
@Component({ /* ... */ })
export class CheckinPage {
private readonly upgradeService = injectAsync(() =>
import('./upgrade-service').then((m) => m.UpgradeService),
);
protected async upgrade(): Promise<void> {
const service = await this.upgradeService();
service.upgrade(/* ... */);
}
}
O import — e, portanto, o carregamento do bundle — só acontece na primeira chamada. Para evitar o atraso dessa primeira vez, dá para pré-carregar com a opção prefetch combinada com onIdle (que carrega quando o navegador está ocioso):
import { injectAsync, onIdle } from '@angular/core';
private readonly upgradeService = injectAsync(
() => import('./upgrade-service').then((m) => m.UpgradeService),
{ prefetch: onIdle }, // carrega quando o browser estiver ocioso
);
Só lembre: para o lazy load funcionar, o serviço injetado precisa ser auto-provido (via @Service() ou @Injectable({ providedIn: 'root' })).
6. debounced: debounce nativo para Signals
Signals, por natureza, não sabem nada sobre tempo — não têm debounceTime nem throttle. O Angular 22 resolve isso com a função debounced, que cria um Resource cujo valor é atualizado com o atraso definido:
import { debounced } from '@angular/core';
const filter = signal('');
const debouncedFilter = debounced(filter, 300); // 300ms
effect(() => console.log(debouncedFilter.value()));
Para formulários, o debounce já vem embutido nos Signal Forms — o debounced cobre todo o resto.
7. Incremental Hydration ligada por padrão
Foco em performance: a hidratação incremental agora vem habilitada por padrão via provideClientHydration(). Para aplicações com SSR, isso significa um ganho real no carregamento inicial, hidratando componentes sob demanda em vez de tudo de uma vez. Se por algum motivo você não quiser, desligue explicitamente com withNoIncrementalHydration() — e há uma schematic de migração para ajudar.
8. HttpClient agora usa FetchBackend por padrão
Mudança discreta, mas com impacto real na migração: o HttpClient passou a usar a Fetch API por padrão, então o withFetch() está depreciado e pode ser removido.
A pegadinha está no progresso de requisições. O antigo reportProgress foi substituído por duas opções dedicadas — e upload progress exige XHR:
// Download (funciona com Fetch)
http.get('/arquivo-grande', { reportDownloadProgress: true, observe: 'events' });
// Upload (exige withXhr())
http.post('/upload', file, { reportUploadProgress: true, observe: 'events' });
Se você usa reportUploadProgress com o FetchBackend, o Angular lança uma exceção de propósito, sinalizando que você precisa de withXhr(). Felizmente, o ng update adiciona withXhr() automaticamente para preservar o comportamento existente.
9. Para quem vive de Microfrontends
Essa seção raramente aparece nos resumos genéricos, mas é justamente o que importa para quem orquestra Module Federation e shells distribuídos. O Angular 22 trouxe melhorias pensadas para esse cenário:
-
ApplicationRef.bootstrapcom config: obootstrap()agora aceita um objeto de configuração análogo aocreateComponent, permitindo subir um microfrontend sob demanda numa área específica da página:
appRef.bootstrap(MyComponent, { hostElement: document.querySelector('#root')! });
Bootstrap sob Shadow Roots: dá para iniciar o Angular diretamente dentro de uma shadow root, com os estilos registrados corretamente no
SharedStylesHost. Mais um passo rumo a uma integração limpa com Web Components.Rotas wildcard com segmentos à frente e atrás (
'foo/**/bar'): antes só com path matcher customizado. Perfeito para shells que precisam carregar o microfrontend certo a partir de um padrão de URL.Auto cleanup de Environment Injectors por rota (
withExperimentalAutoCleanupInjectors): serviços providos no nível da rota finalmente são destruídos ao sair dela, em vez de viverem até a aplicação fechar. Ainda experimental, mas resolve uma dor antiga de vazamento de instâncias (memory leaks).
Melhores práticas para migrar com segurança
Migrar aplicações escaláveis exige estratégia. Um roteiro pragmático:
-
Rode o
ng updatesem medo doOnPush. Ele aplicaEageronde não havia estratégia explícita, então nada quebra. Depois, migre componente a componente paraOnPushe Signals, começando pelas camadas de apresentação mais "quentes". -
Limpe a camada de injeção de dependência. Use o refactor da sua IDE para trocar os
@Injectable({ providedIn: 'root' })mais simples por@Service()— e mantenha@Injectable()onde há providers customizados. -
Adote
injectAsync+onIdlepara enxugar o bundle inicial. Identifique serviços pesados que não são necessários no startup e carregue-os sob demanda, com prefetch no idle. -
Migre GETs simples de RxJS para
httpResource. Onde você usava RxJS só para resolver uma requisição GET, ohttpResourcereduz a complexidade cognitiva drasticamente — sem perder o tratamento de race conditions. -
Confira o
HttpClient. RemovawithFetch()(agora redundante) e garantawithXhr()onde você depende de progresso de upload. Ong updateajuda, mas revise. -
Valide a hidratação no SSR. A Incremental Hydration vem ligada; teste o comportamento e use
withNoIncrementalHydration()se algum fluxo específico precisar do modo antigo.
Para quem está começando — por onde começar de verdade: não tente migrar tudo de uma vez. Rode o
ng update, garanta que o app continua funcionando (graças ao fallbackEager), e só então escolha um componente simples para converter para Signals +OnPush. Sinta o ganho, ganhe confiança, repita. Migração boa é a chata e gradual — não a heroica.
Considerações finais
O Angular 22 é a prova de que o framework do Google se reconstruiu de dentro para fora. Aquela fama de "pesado" e "verboso" ficou para trás: hoje temos reatividade fina, zone-less de verdade e uma Developer Experience de altíssimo nível. Quem segurou as atualizações nos últimos meses agora recebe uma base estável que permite migrar para um desenvolvimento baseado em Signals sem depender de APIs experimentais.
Se você está começando agora, a boa notícia é que está entrando num Angular muito mais simples e direto do que o de alguns anos atrás. E se você já constrói produtos complexos e escaláveis, poucas vezes tivemos ferramentas tão poderosas à disposição.
Gostou da análise? Aplica essas ideias no seu próximo refactor e me conta como foi. Para continuarmos discutindo arquitetura frontend, conteúdo técnico e o mundo do desenvolvimento, se inscreve no canal GhabDev no YouTube e acompanha meus próximos artigos por aqui.
Bons códigos! 💻🚀
📚 Glossário — termos técnicos do artigo
Para quem está começando (ou quer revisar). Em ordem alfabética.
- Assíncrono: algo que não acontece na hora — você pede um dado ao servidor e a resposta chega "depois". O código precisa saber esperar.
- Boilerplate: código repetitivo e cerimonioso que você escreve toda hora sem ele agregar lógica de verdade. Menos boilerplate = menos código chato.
- Bootstrap: o "dar partida" da aplicação Angular — o momento em que o framework inicializa e renderiza o primeiro componente na página.
- Bundle: o pacote final de JavaScript que o navegador baixa para rodar seu app. Quanto maior, mais lento o primeiro carregamento.
- Change detection (detecção de mudanças): o mecanismo que decide quando e onde o Angular re-renderiza a tela depois que algum dado muda.
- Clean Architecture: um jeito de organizar o código em camadas bem separadas (regras de negócio no centro, detalhes como banco e API nas bordas). O objetivo é trocar uma tecnologia sem bagunçar o resto.
- Debounce: técnica para esperar o usuário parar antes de reagir. Ex.: numa busca, em vez de chamar a API a cada letra digitada, você espera 300ms de silêncio e só então busca. Economiza requisições e melhora a experiência.
- Declarativo: você descreve o que quer ("este campo é obrigatório") em vez de escrever passo a passo como fazer. Mais legível.
-
Decorator: aquele
@antes de uma classe (@Component,@Service). É uma anotação que diz ao Angular "trate esta classe de um jeito especial". -
dirty: marca se o usuário já mexeu naquele campo de formulário. Útil para só mostrar o erro "campo obrigatório" depois que ele interagiu, em vez de gritar erro com o formulário ainda em branco. -
Eager/Default: a estratégia "antiga e cara" de change detection — a cada ciclo o Angular varre a árvore inteira de componentes procurando mudanças. Funciona, mas desperdiça processamento. No Angular 22 virouEagere está depreciada. - Enterprise: aplicações grandes, de empresas, com muitos times e anos de manutenção pela frente.
-
Fetch vs. XHR: duas formas de o navegador fazer requisições HTTP. O XHR (
XMLHttpRequest) é o jeito antigo; o Fetch é o moderno, baseado em Promises (mais limpo) e melhor para streaming. A única coisa que o Fetch ainda não faz bem é relatar progresso de upload. - Fortemente tipado: o TypeScript "sabe" o formato exato dos seus dados e te avisa no editor se você errar um campo, antes de rodar. Menos bug em produção.
- Framework: uma "caixa de ferramentas" estruturada que já resolve problemas comuns (rotas, formulários, requisições) para você não reinventar a roda.
- Hydration / Incremental Hydration: o processo de "dar vida" ao HTML estático vindo do servidor — o Angular conecta os eventos e a interatividade. Incremental significa fazer isso aos poucos, só nas partes que o usuário vê/usa, em vez de tudo de uma vez.
- Injeção de dependência (DI): em vez de a sua classe criar sozinha as coisas de que precisa (ex.: um serviço de API), ela apenas pede e o Angular entrega. Deixa o código mais fácil de testar e manter.
- Interop / migração incremental: "interop" é a capacidade de o código novo conversar com o antigo. "Migração incremental" é atualizar o projeto aos poucos, um pedaço de cada vez, sem reescrever tudo num único e arriscado big bang.
- Lazy loading (carregamento sob demanda): em vez de baixar tudo de uma vez, você adia o download de partes pesadas para o momento em que forem realmente usadas. A página abre mais rápido.
- Memory leak (vazamento de memória): quando algo continua ocupando memória mesmo depois de não ser mais necessário. Em apps longos, vazamentos acumulam e deixam tudo lento.
- Microfrontends: dividir uma aplicação grande em vários "mini-apps" independentes, cada um tocado por um time diferente, que se juntam numa só tela. É o "microsserviços" do mundo frontend.
- Module Federation: a tecnologia (do Webpack) que permite a esses mini-apps compartilharem código e serem carregados em tempo de execução.
-
ng update: comando do Angular CLI que atualiza seu projeto de uma versão para outra, aplicando migrações automáticas quando possível. -
onIdle/ prefetch: "prefetch" é carregar algo antes de precisar, de forma discreta. OonIdlefaz isso nos momentos em que o navegador está ocioso (usando a APIrequestIdleCallback). Assim, quando o usuário clicar, já está tudo pronto. -
OnPush: estratégia "econômica" de change detection — o Angular só verifica o componente quando recebe uma entrada nova, um evento, ou um Signal muda. Resultado: mais performance. -
providedIn: 'root': diz que existe uma única instância do serviço para o app inteiro (padrão singleton). Antes você escrevia isso à mão; agora o@Service()já assume por padrão. -
Race condition (condição de corrida): quando o usuário digita rápido e dispara várias buscas seguidas, a resposta de uma busca antiga pode chegar depois e sobrescrever o resultado certo com um errado. O
httpResourceresolve isso sozinho. - Reativo / reatividade: a UI reage sozinha quando os dados mudam, sem você mandar "atualiza a tela" manualmente.
- Reactive Forms vs. Template-Driven: as duas formas antigas de fazer formulário no Angular. Reactive Forms monta o formulário no TypeScript (mais controle, mais verboso); Template-Driven monta no HTML (mais simples, menos poderoso). Os Signal Forms unificam o melhor dos dois.
- Requisição HTTP: o pedido que seu app faz a um servidor ("me dá a lista de voos"). O servidor responde com os dados.
- Resource: um "pacote inteligente" que faz a requisição, guarda o resultado e te entrega de bandeja três estados: carregando, erro e o valor final.
-
RxJS /
switchMap: o RxJS é uma biblioteca de programação reativa baseada em streams (fluxos de dados ao longo do tempo). OswitchMapé um operador dela que, quando chega um pedido novo, cancela o anterior — exatamente o que evita resultados bagunçados. - Schema: a "planta" que descreve as regras de validação de um formulário (quais campos, quais limites). Zod e Valibot são bibliotecas populares para isso.
- Schematic: um script de automação do Angular que aplica mudanças no seu código para você (renomear, mover configs, etc.) durante uma migração.
- Service (serviço): uma classe que concentra lógica reutilizável e sem tela — ex.: buscar dados, fazer cálculos, guardar estado. Vários componentes podem compartilhar o mesmo serviço.
- Shell: o app "casca" que orquestra e carrega os microfrontends dentro de si.
- Signals: a forma moderna do Angular guardar um valor que avisa automaticamente quem depende dele quando muda — tipo uma planilha onde a célula B se recalcula sozinha quando A muda.
- SSR (Server-Side Rendering): o servidor monta o HTML já pronto e manda para o navegador. O usuário vê a página rápido, antes mesmo do JavaScript carregar. Bom para performance e SEO.
- Startup: o tempo entre o usuário abrir a página e ela ficar utilizável.
- Web Components / Shadow Root: Web Components são componentes de UI que funcionam em qualquer framework. A shadow root é uma "bolha" isolada que protege os estilos do componente de vazarem (e de sofrerem interferência) — ótimo quando vários times misturam código.
- Wildcard (``):** um "coringa" na definição de rota que casa com qualquer caminho. Útil quando você não sabe de antemão a URL exata, só o padrão.
-
Zone-less / Zone.js: o
Zone.jsé uma biblioteca que historicamente "vigiava" tudo que acontecia na aplicação para saber quando atualizar a tela. Zone-less é o Angular funcionando sem ela — algo possível graças aos Signals, e mais rápido.
Fontes técnicas: anúncio oficial do Angular v22 (angular.dev) e a análise detalhada de Manfred Steyer (ANGULARarchitects), ambos de junho de 2026.
Top comments (0)