Angular 19 represents a major maturation step for the platform, especially around signals which now become the cornerstone of change detection. This version consolidates the foundations laid in 18 by removing zone-based change detection by default, forcing projects to embrace signal-based reactivity. This isn't a cosmetic revolution: it's a deep architectural shift affecting performance, maintainability, and how you reason about application state. If you were still hesitant about signals in 18, you won't have a choice in 19.
The end of zone-based change detection
The removal of ZoneJS by default is the most impactful change. In 18, you could still configure an application without signals and rely on zone.js to detect asynchronous changes. In 19, that's gone: the framework assumes you're using signals and OnPush change detection. Concretely, this means any observable not converted to a signal will no longer trigger automatic change detection. If you have services emitting observables and components consuming them via the async pipe, you must convert those observables to signals using toSignal(). This is a migration that can be progressive but must be planned. For existing applications, Angular CLI provides partial codemods, but expect to revisit your change detection patterns component by component.
Signals and computed: the reactive core
Signals are no longer experimental: they're the standard. The syntax remains identical but it's now the privileged path. Computed signals also gain robustness with better dependency tracking and finer-grained change detection. If you had computeds that recalculated too often in 18, you'll see a clear improvement. Angular also provides additional helpers like effect() which better handles cleanup and asynchronous dependencies. Key point: effects are no longer considered "bastard code", they're part of the recommended state management strategy. This enables cleaner patterns for side-effects like logging, deferred API calls, or state synchronization.
Reactive Forms: a new API suite
Angular 19 introduces a new API for reactive forms, better aligned with signals. FormGroup and FormControl now accept signals as input and emit signals as output. Instead of subscribing to valueChanges with an observable, you can directly read a form control's value from a signal. This improvement reduces memory leaks and makes form code much more readable. Concrete example: instead of this.form.valueChanges.pipe(debounceTime(300), distinctUntilChanged()).subscribe(...) , you can now benefit from declarative validation with signals that naturally synchronize. FormBuilder and FormControl accept a new nonNullable configuration argument, reducing typing boilerplate.
export class MyFormComponent {
form = new FormGroup({
email: new FormControl('', { validators: [Validators.required], nonNullable: true }),
password: new FormControl('', { validators: [Validators.required], nonNullable: true })
});
email = toSignal(this.form.get('email')!.valueChanges, { initialValue: '' });
isValid = computed(() => this.form.valid);
}
Dependencies and minor breaking changes
Zone.js migration is straightforward but requires rigor. Zone.js imports in polyfills.ts can be removed if you only needed them for Angular. However, if third-party libraries (like Jasmine or some charting libraries) still depend on zone.js, you must keep them. Angular 19 provides an exhaustive list of breaking changes, but most relate to internal or long-deprecated APIs. The JIT compiler has been removed: all builds now use Ivy and esbuild by default. If you had custom JIT configuration, you must switch to AOT.
Common pitfalls during migration
The most common pitfall is assuming toSignal() is a magic bullet for observables. In reality, toSignal() creates a subscription that persists as long as the signal exists. If you use it in a singleton service, you must manually handle unsubscribe or use an appropriate destruction strategy. Second pitfall: forgetting that signals are synchronous by default. If you try to immediately read a signal's value derived from an asynchronous observable, you'll get the initial value, not the updated one. Third common pitfall: mixing reactive patterns. Having half your application in signals and the other half in observables creates performance and maintainability friction. Plan a progressive but coherent migration.
Tools and resources for migration
Angular CLI 19 provides automated codemods with ng update @angular/core . These codemods aren't perfect but handle most common cases: basic observable-to-signal conversion, import updates, zone.js removal from polyfills. For complex migrations, use Angular's provided schematics or write your own. Unit tests must be reviewed: TestBed and async fixtures behave differently with signals. Angular provides detailed migration guides with code examples per domain (forms, HTTP, routing).
Migrating to Angular 19 is not a cosmetic patch: it's an opportunity to refactor your reactive architecture around signals. The path is clear, tools exist, but success depends on understanding the paradigm shift, particularly abandoning zone-based change detection. Start with tests, then services, then components. Accept that this migration will take time on a large codebase, but the gains in performance and maintainability are worth it.