Modern Angular for Production Teams

Modernization without a wait list is a campaign. With one, it's a sequence. Five Angular majors landed in 30 months between v16 and v21. The three documents that get a production team from drift to shipment, with a review gate you can defend in thirty seconds.

The decision you actually make at PR review

Five Angular majors landed between v16 (May 2023) and v21 (November 2025), per the official release reference. That cadence works when a team has a written reference for what to adopt, spike, or explicitly wait on. Without one, every modernization PR re-opens the same debate.

You're the one approving modernization PRs on an Angular 16-21 team in production (tech lead, staff engineer, or the senior the team consults). A PR lands in your queue: a new feature uses Signals for local state. You have thirty seconds. Approve, send back, or escalate?

A lot of modernization noise lives in those thirty seconds. The framework keeps shipping. The team keeps proposing adoption. You keep approving or pushing back without a written reference. Three quarters in, half the codebase looks Angular 16-era and the other half looks Angular 21, and nobody can explain the split.

Three documents your team agrees on before any modernization proposal enters review absorb most of that pressure. The list of patterns approved as default. The list of patterns under spike. The list of patterns explicitly waiting.

Three lists your team should maintain

Each list answers a different review question.

ListLives inReviewed when
Default for new codeLint rules and style guideOn every framework major
Spike candidatesPer-feature ADRsOn spike close
Explicitly waitingQuarterly decisions logQuarterly, or on API status change

What goes in each list

The first list is the 'yes' bucket. New components use standalone, local state uses Signals, control flow uses @if/@for/@switch, dependency injection uses inject. Codified in the linter so PR review does not relitigate the decision.

RxJS stays the default for genuinely async streams (autocomplete debouncing, WebSockets, polling, cancellation). Signals replace local state that used to live in a BehaviorSubject. The two are not in competition; they answer different questions.

The second list is the 'maybe, in a branch' bucket. Zoneless in an existing app (stable since v20.2, default in new projects from v21, but removing Zone.js from a legacy still belongs in a spike). Vitest for a large suite. SSR/hydration for a public route. Each gets a written ADR (context, hypothesis, validation criteria, rollback path) before any code touches the main branch.

The third list is the one most teams skip. Features that look modern, sound modern, and do not fit critical production flows yet.

As of June 2026, the wait list just earned its keep. Signal Forms, the rxResource and resource APIs, and Angular Aria were all on it through v21, and v22 (June 2026) graduated the three to stable, which is exactly the trigger the list exists to catch: they move from 'waiting' to 'adopt for new code.' What stays on the list now is the AI-runtime surface, like WebMCP, which is still experimental and does not belong in billing, compliance, or any flow you cannot easily revert.

The wait list is not 'against' these features. It is 'not yet, and here's the trigger that would move them off the list.' Recheck on every Angular major.

Short ADR template for a spiketext
# ADR: spike Vitest on the orders package

Status: proposed
Context: orders test suite (~280 specs) runs in 4m20s on Karma; team reports flaky failures around fakeAsync.
Decision: migrate 1 module slice to Vitest, measure runtime, CI stability, and migration cost. No production code touched.
Scope: orders/specs only. Other packages untouched.
Out of scope: changing component test patterns, replacing TestBed.
Risks: hidden Zone.js dependencies in shared helpers; CI parallelism differences.
Validation: runtime, flake rate (7-day window), team review of migration diff.
Rollback: revert the package; keep ADR for next attempt.

The 'explicitly waiting' list deserves more care than the other two

In three Angular codebases I've helped modernize between 2023 and 2026, the list teams never had was the third one. They had defaults. They had spikes. They never had a written record of what they had decided not to adopt yet, or why.

A team that has documented what it adopts is a team that has thought about modernization. A team that has documented what it is explicitly waiting on is a team that has decided.

Without the third list, every modernization PR turns into a debate from scratch (because nobody knows what was already decided). With it, the review question becomes specific: 'this proposes Signal Forms for the billing form, but the wait-list flagged Signal Forms as developer preview. What changed in the API status?'

The list does not have to be long. Three to five features at any time is enough. Each entry needs (1) what you are not adopting, (2) why (status, blast radius, dependency cost), (3) the trigger that would move it off the list.

How to communicate 'we are not adopting that yet' without sounding conservative

Senior leadership often hears 'we are waiting on Signal Forms' as 'we are behind.' That is a translation problem, not a strategy problem.

The reframe: modernization without a wait list is a campaign. Modernization with one is a sequence. Sequences ship; campaigns drift.

Specific phrases that have worked in my reviews: 'We've staged adoption to match the API's production track record.' 'We're deferring X until we see how it interacts with our forms architecture.' 'The framework direction is right; the current status (experimental, developer preview) does not fit our critical flows yet.'

These phrases name the discipline and give the upstream conversation a place to land.

When to revisit each list

Calendar-based reviews fail because the framework does not respect calendars. Trigger-based reviews work.

When the Angular team communicates adoption, it tends to communicate with production data. In the v20 announcement, Minko Gechev (Angular team lead) highlighted that YouTube using Angular Signals with Wiz reduced input latency on Living Room by 35%. A team that maintains the wait-list learns to read that kind of signal before promoting features into 'default.'

Triggers worth wiring into your process:

TriggerList to revisitWhy
New Angular major (v22, v23)All threeDefaults, status labels, deprecations may shift
Production track record (6+ months on an experimental API)Explicitly waitingDirect promotion candidate
Team capacity changeSpike candidatesAdjust experiment cost budget
Critical bug in a 'default' APIDefault for new codeDemote, document, communicate

The point

For a production team, what survives a framework major is the decisions you wrote down, where they live, and how the team finds them at 9pm on a Friday when a release manager asks 'are we using Signal Forms in billing or not?'

Reusable artifact

Review-gate questions for a modernization PR

  • Which of the three lists does this PR's pattern belong to?
  • If it claims a 'default' pattern, is that codified in the linter?
  • If it's a spike, where's the ADR with hypothesis, validation, and rollback?
  • If the API is on the 'explicitly waiting' list, what changed in its status?
  • If none of those apply, what list should this PR be establishing?

Sources checked

Modern Angular Playbook

This article is one play.

The Modern Angular Playbook collects the diagnostic, the adoption matrix, eleven plays, and the 30-day plan. Free, in English and Portuguese.

You get both PDFs by email, through the Dojo IA list.

Open playbook →

André Ramosavailable for remote roles, UTC−3Get in touch →

Related

Note · 6 min

What to Adopt, Spike, or Wait On in Angular 21

An adoption filter for Angular 21: what belongs in code already changing, what deserves a branch, and what should stay away from critical flows.

Read article →

Guide · 7 min

Standalone Without Turning NgModules Into a Villain

A practical rule for using standalone components, route providers, and remaining NgModules in mature Angular applications.

Read article →

Guide · 9 min

Facade Pattern in Angular: When Components Know Too Much

A production Angular guide to the Facade Pattern: when to create one, what it should own, what it should not hide, and how to test the boundary.

Read article →