Angular 20 to 21 Upgrade: The Practical Survival Guide
Source: Dev.to
Introduction
A clear and concise guide to upgrading from Angular 20 to 21. It covers the essentials like the Karma removal, the new default Zoneless mode, automatic HttpClient, and how to fix breaking builds.
If you thought Angular 20 was a big shift, welcome to Angular 21. While version 20 focused on stabilizing Signals, version 21 removes the old guard. The “Angular Way” has fundamentally changed: zone.js is optional, Karma is dead, and RxJS is slowly retreating to the edges. This isn’t just an update; it’s a new ecosystem. Below is what will break and how to fix it.
Testing Changes: Karma → Vitest
What breaks
- Custom
karma.conf.jsor reliance on specific Karma plugins/reporters will cause failures. - Tests that mock the absence of
HttpClientmay also break (see the HttpClient section).
The Fix
-
New projects: Vitest is provided out of the box. It’s faster, cleaner, and uses Vite.
-
Existing projects: You can continue using Karma for now, but the CLI will warn you.
-
Migration: Run the schematic
ng generate @angular/core:karma-to-vitestIt converts standard configs automatically. Custom Webpack hacks in your test setup will need manual rewriting for Vite.
HttpClient Changes
The Change
HttpClient is now injected by default in the root injector. You no longer need to add provideHttpClient() in app.config.ts or import HttpClientModule unless you need custom configuration.
What breaks
- Tests that expect
HttpClientnot to be present may fail. - Complex interceptor ordering in mixed NgModule/Standalone apps may exhibit subtle behavior changes.
The Fix
- Remove explicit
provideHttpClient()calls unless you pass configuration options (e.g.,withInterceptorsorwithFetch). - Verify interceptor execution order after the change.
Zoneless Mode (zone.js optional)
The Change
New apps generated with ng new exclude zone.js by default.
What breaks
- Existing apps continue to import
zone.jsfrompolyfills.ts(no immediate breakage). - Copy‑pasting code from a new v21 tutorial into a v20 app may assume Zoneless behavior, leading to “changed after checked” errors or views that don’t update.
Recommendation
Understand the differences between Zone‑based and Zoneless change detection before mixing paradigms.
New Features
Reactive Forms with Signals
import { form, field } from '@angular/forms/signals';
import { Validators } from '@angular/forms';
// Define a reactive form model
const loginForm = form({
email: field('', [Validators.required, Validators.email]),
password: field('', [Validators.required])
});
// Access values directly as signals!
console.log(loginForm.value().email);
- Why use it: Type‑safe by default and doesn’t require deep RxJS knowledge.
- Status: Experimental – suitable for new features, but avoid rewriting large existing flows just yet.
Headless Accessibility Primitives
<Option 1>
<Option 2>
Instead of manually managing aria-expanded and role="button", use these directives to handle a11y logic while you style the components.
Regex Literals in Templates
@if (email() | match: /@company\.com$/) {
Employee
}
Small but mighty: you can now use regex literals directly in templates, perfect for simple @if logic without helper functions.
Upgrade Steps
1. Backup
Commit everything. Seriously.
2. Update the Global CLI
# Optional: Uninstall the old global version first to avoid conflicts
npm uninstall -g @angular/cli
# Verify the npm cache
npm cache verify
# Install the latest global CLI version
npm install -g @angular/cli@latest
3. Update the Local Project
ng update @angular/cli@21 @angular/core@21
4. Run Diagnostics
Look for deprecated usages such as ngClass (soft‑deprecated in favor of [class.my‑class]) and identify standalone migration opportunities.
5. Check Your Tests
ng test
- If it explodes, decide:
- Path A – Keep Karma (add
@angular/build:karmamanually if removed). - Path B – Migrate to Vitest (recommended).
- Path A – Keep Karma (add
6. Optional: Go Zoneless
ng generate @angular/core:zoneless-migration
This is “Agentic” territory. See our MCP Guide for how to let AI handle this complex refactor.
Conclusion
Angular 21 is the “clean slate” release. It sheds the weight of the last decade—Zone, Karma, and heavy module patterns—to compete with modern frameworks like Svelte and Solid. The upgrade may be bumpy due to testing changes, but the destination—a faster, simpler, signal‑driven framework—is absolutely worth it.