DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Angular 19: Mastering `ChangeDetectionStrategy.OnPush` in the Era of Signals

ChangeDetectionStrategy.OnPush

In Angular 19, performance and reactivity have reached new heights with the maturity of Signals, standalone components, and the continued use of ChangeDetectionStrategy.OnPush. But how does OnPush actually work—and why is it more powerful than ever in Angular 19?

Let’s break it down.


What Is Change Detection in Angular?

Change detection is Angular’s internal mechanism to keep your UI in sync with your application state.

By default, Angular uses the Default strategy, which:

  • Checks every component on each event (clicks, HTTP, setTimeout, etc.)
  • May result in unnecessary performance costs as your app scales

ChangeDetectionStrategy.OnPush

import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
  selector: 'app-optimized',
  templateUrl: './optimized.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class OptimizedComponent {}
Enter fullscreen mode Exit fullscreen mode

This tells Angular:

Only run change detection for this component if:

  • An @Input() reference changes
  • An event fires in the component
  • You explicitly call markForCheck()
  • A Signal or Observable emits a new value

Angular 19 + Signals = Next-Level Performance

In Angular 19, Signals are stable and fully integrated with change detection.

import { signal } from '@angular/core';

@Component({
  selector: 'app-counter',
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  template: `
    <button (click)="count.update(c => c + 1)">Increment</button>
    <p>Count: { count() }</p>
  `,
})
export class CounterComponent {
  count = signal(0);
}
Enter fullscreen mode Exit fullscreen mode

✔️This works beautifully with OnPush, and you don’t need to manually trigger change detection.


Benefits of Using OnPush

Benefit Description
⚡ Fast Rendering Skips unchanged components
🧠 Smart Reactivity Integrates cleanly with signal(), async, and Observables
🧼 Cleaner Code Encourages immutability and unidirectional flow
📦 Efficient App Reduced computation = better user experience

Common Pitfalls with OnPush

Pitfall What Happens
Mutating objects/arrays No re-render (Angular sees no reference change)
Forgetting markForCheck() UI appears stuck
Using @Input() with mutation Changes not detected unless ref changes

❌Bad

this.items().push(newItem); // Mutates in place
Enter fullscreen mode Exit fullscreen mode

✅ Good

this.items.update(prev => [...prev, newItem]); // Creates a new array
Enter fullscreen mode Exit fullscreen mode

When to Use OnPush

  • Presentational (dumb) components
  • Components relying on Signals or RxJS
  • Performance-critical sections of your app
  • Any place where data is passed via @Input() or reactive streams

Final Thoughts

Angular 19 offers a powerful synergy between Signals and OnPush. When used together, they enable ultra-performant, low-overhead UIs that scale beautifully.

Use ChangeDetectionStrategy.OnPush in all your stateless or reactive components—especially when you’re using Signals or async.

Happy coding, and may your trees stay clean and your signals stay sharp! ⚡

angular #typescript #signals #frontend #architecture

Top comments (1)

Collapse
 
k_h_412a87d7d1e9d31be32 profile image
K. H.

Not true. I tried it out, as of today, in angular 19 - you can change objects and arrays directly and angular will show the changed values, even when using the 'onPush' strategy. (I don't think it should, but there you go)