Jun 28, 2025 · Updated Jul 15, 2026

Upgrade Angular 19 to 20: No Breaking Changes Missed

angularangular20Angular20PDFsignalszonelessclissrfrontendvitest

Walk through every step to migrate from Angular 19 to 20 — signals, control flow, the new @angular/build package, and the catches most guides skip.

TL;DR — upgrade Angular 19 to 20 in 3 steps:

# Prerequisites: Node.js 20.11.1+ and TypeScript 5.8+ npm install -g @angular/cli@latest ng update @angular/cli@20 @angular/core@20 ng test # if it fails, see the Karma fix below

What actually breaks: afterRender() is renamed to afterEveryRender() (no auto-migration), TestBed.get() is removed, and @angular-devkit/build-angular is replaced by @angular/build — which drops Karma. Every fix is covered step by step below.

1. The Full Story Behind Karma’s Removal: Beyond a Broken Build

The immediate issue when upgrading is that ng test will fail. The reason is a fundamental change in Angular’s build tools.

Why did Angular drop Karma?

With Angular 20, the default build package changes from @angular-devkit/build-angular to the new @angular/build. This new package no longer includes the Karma plugin used by legacy test setups.

The web ecosystem has moved on to faster test runners like Vitest and Jest that use modern tools like Vite and esbuild. Karma had become a bottleneck.

What the new world looks like (Vitest/Jest)

Angular’s experimental test runner, now powered by Vitest, is the future. Migrating means your unit tests will run in a fast, modern Node.js-based environment.

The “temporary fix” explained

npm install @angular-devkit/build-angular --save-dev

This command forces the CLI to fall back to the old compiler that still supports Karma. It’s a compatibility bridge — but the message is clear: start planning your migration to Jest or Vitest soon.

How Do I Migrate from Karma to Vitest in Angular 20?

Run the official schematic instead of reinstalling the legacy builder:

ng generate @angular/core:karma-to-vitest

This auto-converts your test configuration and updates angular.json to use the @angular/build:unit-test builder with runner: 'vitest'. Standard Karma setups migrate cleanly; custom Webpack hacks in karma.conf.js need manual rewriting afterward.


2. Prerequisites

Before starting the update process, make sure you meet the following:

  • Node.js: Version 20.11.1 or later
  • TypeScript: Version 5.8 or later
  • Project backup: Commit all current changes in Git

3. How to Update: CLI Command and Comparison

Update Command

Make sure you’re running Node.js v20.11.1 or later:

ng update @angular/cli @angular/core

If you use Angular Material:

ng update @angular/cli @angular/core @angular/material

Manual intervention required

To reinstall the old compiler with Karma support:

npm install @angular-devkit/build-angular --save-dev

This wasn’t required in earlier versions but is now mandatory if you want to keep using Karma.

Compared to earlier upgrades

  • Angular v19: ng update just worked.
  • Angular v20: You must manually reinstall the old builder for Karma.

4. Control Flow: More Than Syntactic Sugar

@for replaces *ngFor and is a major improvement.

Old syntax

<div *ngFor="let item of items; trackBy: trackItemById">{{ item.name }}</div>

New syntax

@for (item of items; track item.id) { <div>{{ item.name }}</div> } @empty { <div>No items to display.</div> }
  • track is mandatory and encourages best practices.
  • @empty improves DX by removing the need for separate @if.

Automated migration and performance

Use the CLI to automatically refactor templates to the new control flow syntax:

ng generate @angular/core:control-flow

General Best Practices and Further Migrations

You can also migrate to other modern Angular features:

ng generate @angular/core:standalone ng generate @angular/core:inject ng generate @angular/core:route-lazy-loading ng generate @angular/core:signal-input-migration ng generate @angular/core:signal-queries-migration ng generate @angular/core:output-migration

These commands allow for a comprehensive update of an Angular app to leverage the latest patterns.


5. Standalone by Default: A Fundamental Architectural Shift

By explicitly listing dependencies using the imports array at the component level, each component becomes self-contained. This:

  • Clarifies your architecture
  • Improves tree-shaking
  • Results in smaller bundles

6. Zoneless: Escaping the “Magic” of Change Detection

In a zone-less world, the UI only updates when you explicitly tell it to.

Signals are the main tool here.

mySignal.set(newValue);

This directly tells Angular to update only the DOM parts that use that signal. It’s a surgical, predictable, and high-performance approach.


7. New Naming Convention: Why It Feels Complicated

Angular 20 introduces a new official naming convention that drops traditional suffixes.

Old namingNew namingIntent
user-profile.component.tsuser-profile.tsUI component
auth.service.tsauth-store.tsState management
highlight.directive.tshighlight.tsDirective
user-api.service.tsuser-api.tsHTTP requests

The goal is to focus on intent rather than technical type: a class that manages state is a “store,” one that makes HTTP requests is an “api.”

Naming rules

  • Use dashes: user-profile.ts
  • Match class and filename
  • Keep .spec.ts for tests
  • Avoid generic names like utils.ts
  • Co-locate related files

Feature-based folder structure

src/ ├── core/ │ └── auth/ │ ├── auth-store.ts │ ├── login.ts │ └── register.ts ├── features/ │ └── users/ │ ├── user-profile.ts │ ├── user-api.ts │ └── user-settings.ts

Benefits

  • Cleaner Git diffs
  • Intention-oriented code
  • Easier onboarding

8. Important Detail: browserslist and Browser Support

Angular 20 no longer supports Opera officially.
If you list Opera in your browserslist, you may need to remove it.

Other non-mainstream browsers may also lose support, potentially triggering warnings or build issues.


On Angular 20 and ready for more? Continue with Angular 20 to 21: Breaking Changes and How to Fix Them, or see every migration path in the Angular Upgrade Guide.

Written by

Antonio Cárdenas

Google Developer Expert in Angular · Verified GDE profile · Google Developers profile

My technical writing reaches 100,000+ developers in English and Spanish. I've migrated production Angular apps from v8 to v22 — everything I publish is built from real project work, not documentation re-reads.

Frequently asked questions

FAQs

How do I upgrade from Angular 19 to Angular 20?

Run ng update @angular/cli@20 @angular/core@20 in your project. Before running, ensure you are on TypeScript 5.8+ and Node.js 20+. Angular 20 replaces @angular-devkit/build-angular with the new @angular/build package, which drops Webpack dependencies. After updating, run ng test — if it fails, you may need to migrate from Karma to Vitest using ng generate @angular/core:karma-to-vitest.

What breaks when upgrading from Angular 19 to 20?

The main breaking changes in Angular 20 are: (1) afterRender() is renamed to afterEveryRender() with no auto-migration — you must update this manually; (2) TestBed.get() is finally removed — use TestBed.inject() instead; (3) InjectFlags enum is removed; (4) DOCUMENT token moved from @angular/common to @angular/core; (5) ng-reflect-* attributes are off by default in dev mode; (6) fixture.autoDetectChanges(false) throws in zoneless tests.

Does Angular 20 require TypeScript 5.8?

Yes. Angular 20 requires TypeScript 5.8 as the minimum version. TypeScript 5.8 was supported since Angular 19.2, but Angular 20 makes it mandatory. You must upgrade before running ng update.

What is @angular/build and how does it replace @angular-devkit/build-angular?

@angular/build is the new, leaner build package introduced in Angular 20 that replaces @angular-devkit/build-angular. It drops transitive Webpack dependencies, reducing node_modules by roughly 200 MB, and fully embraces Vite/esbuild. New projects generated with ng new use @angular/build directly. The ng update migration handles this automatically for existing projects.

Is ng test broken after upgrading to Angular 20?

ng test may fail after upgrading if you have a custom karma.conf.js or rely on Karma-specific plugins. Angular 20 introduced Vitest as an experimental test runner via the @angular/build:unit-test builder. To migrate from Karma to Vitest, run ng generate @angular/core:karma-to-vitest. Standard Karma configurations are auto-migrated well; custom Webpack hacks in test setup require manual rewriting.

Keep reading

Building something with Angular?

I write about Angular architecture, Signals and the tooling around them — migration guides, real upgrade paths, and the catches most posts skip.

Browse all articlesAbout me

More from the blog