← Back to Articles         
What is ChangeDetectionStrategy.OnPush?

What is ChangeDetectionStrategy.OnPush?

Published on 02 Oct 2026     7 min read Angular
Change Detection

1. What is ChangeDetectionStrategy.OnPush?

What is it?

ChangeDetectionStrategy.OnPush is an Angular change-detection strategy that allows Angular to skip checking a component subtree when Angular has no indication that the subtree needs to be refreshed.

It is mainly used to reduce unnecessary change-detection work and improve performance, particularly in larger applications.

changeDetection: ChangeDetectionStrategy.OnPush

The simple idea is:

Default
   ↓
Angular normally checks the component
during change-detection traversal

OnPush
   ↓
Angular can skip the component subtree
unless it needs checking

Full Simple Sample Program

This example demonstrates an important OnPush concept: input reference changes.

app.ts — Parent

import { Component } from '@angular/core';
import { UserCard } from './user-card';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [UserCard],
  template: `
    <h1>OnPush Example</h1>

    <app-user-card [user]="user"></app-user-card>

    <button (click)="changeUser()">
      Change User
    </button>
  `
})
export class App {

  user = {
    name: 'Syed'
  };

  changeUser(): void {
    this.user = {
      name: 'Mohamed'
    };
  }
}

user-card.ts — Child

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

@Component({
  selector: 'app-user-card',
  standalone: true,
  template: `
    <h2>User: {{ user.name }}</h2>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserCard {

  @Input() user!: { name: string };
}

How Does It Work?

Initially:

user = {
  name: 'Syed'
};

The child receives:

user object
    ↓
User: Syed

When we click:

<button (click)="changeUser()">

the parent executes:

this.user = {
  name: 'Mohamed'
};

Notice that we created a new object.

Old object reference
       ↓
{ name: 'Syed' }

New object reference
       ↓
{ name: 'Mohamed' }

The child's input reference has changed.

Angular can therefore check the OnPush child, and the UI becomes:

User: Mohamed

Important OnPush Problem: Mutating an Object

Suppose instead we write:

changeUser(): void {
  this.user.name = 'Mohamed';
}

We changed a property, but the user object itself is still the same reference.

Before:

user ──────► Object A
             name = Syed


After:

user ──────► Object A
             name = Mohamed

Same Object A

For an OnPush child receiving that object as an input, this kind of mutation can prevent the input change itself from causing the child to be checked.

That is why immutable updates are a common pattern with OnPush.

Prefer:

this.user = {
  ...this.user,
  name: 'Mohamed'
};

Now:

Old:

user ──────► Object A


New:

user ──────► Object B

The reference changed.


When Can an OnPush Component Be Checked?

A common oversimplification is:

OnPush checks only when @Input changes.

That's not correct.

Important situations include:

1. Input changes

this.user = {
  name: 'Mohamed'
};

A new input reference/value can cause the OnPush component to be checked.

2. An event occurs in the component

<button (click)="increment()">
  Increment
</button>

An event handled in the component/subtree can cause it to be checked.

3. A Signal used by the template changes

count = signal(0);

increment() {
  this.count.update(x => x + 1);
}

Angular tracks the signal dependency and knows the consuming view needs refreshing.

4. AsyncPipe receives a new value

For example:

<p>{{ user$ | async }}</p>

AsyncPipe marks the view for checking when a new value arrives.

5. The component is manually marked

For example:

changeDetectorRef.markForCheck();

Advantages of OnPush

OnPush can:

  • Reduce unnecessary component checks
  • Improve performance in large component trees
  • Work well with immutable state
  • Work well with Signals
  • Work well with Observables and AsyncPipe
  • Encourage predictable state-management patterns

Key Points

  • OnPush is an Angular change-detection strategy.
  • It allows Angular to skip unnecessary component subtrees.
  • It is not correct to say "OnPush checks only when @Input changes."
  • Input reference changes are particularly important for objects and arrays.
  • Avoid directly mutating input objects when relying on immutable OnPush patterns.
  • Signals work very naturally with OnPush.

2. Default vs OnPush Change Detection — What Is the Difference?

The main difference is how aggressively Angular checks component subtrees during change detection.

Default

changeDetection: ChangeDetectionStrategy.Default

Angular uses normal eager checking when traversing the component tree.

OnPush

changeDetection: ChangeDetectionStrategy.OnPush

Angular can skip an OnPush component subtree when it has no reason to believe the subtree needs refreshing.


Simple Comparison

Feature Default OnPush
Checking behavior Eager/normal Can skip unaffected subtrees
Performance optimization Less aggressive More aggressive
Object mutation Often appears to work Can cause stale child UI
Immutable objects Optional Strongly recommended
Signals Supported Excellent combination
AsyncPipe Supported Excellent combination
Ease of use Simpler Requires better state discipline
Large applications Works Often useful for optimization

Example

Imagine:

App
│
├── Header
│
├── ProductList
│    │
│    ├── Product 1
│    ├── Product 2
│    └── Product 3
│
└── Footer

With normal Default checking, Angular performs its standard eager traversal when change detection runs.

Conceptually:

Change Detection
       ↓
      App
       ↓
  ┌────┼────────┐
  ↓    ↓        ↓
Header Products Footer
        ↓
      Products

With OnPush, Angular can skip subtrees that don't need checking:

Change Detection
       ↓
      App
       ↓
  ┌────┼─────────┐
  ↓    ↓         ↓
skip  Products   skip

This becomes valuable when an application has hundreds or thousands of components.


Very Important: Primitive vs Object Inputs

This is one of the most important OnPush interview concepts.

Primitive

name = 'Syed';

Then:

this.name = 'Mohamed';

The value changed:

Syed → Mohamed

Straightforward.

Object

user = {
  name: 'Syed'
};

Don't rely on mutating it:

this.user.name = 'Mohamed';

The object reference remains the same.

Prefer creating a new object:

this.user = {
  ...this.user,
  name: 'Mohamed'
};

Now the reference changes.

Same idea with arrays.

Avoid:

this.products.push(newProduct);

Prefer:

this.products = [
  ...this.products,
  newProduct
];

Conceptually:

Mutation

Array A
  ↓
push()
  ↓
Array A

Same reference

versus:

Immutable update

Array A
  ↓
create new array
  ↓
Array B

New reference

Default vs OnPush — Easy Way to Remember

Think of Default as:

"Check normally whenever Angular performs its change-detection traversal."

Think of OnPush as:

"Skip my subtree unless Angular knows I need checking."

So:

DEFAULT
========

Change Detection
      ↓
Check normally
      ↓
Evaluate bindings
      ↓
Update DOM if required


ONPUSH
======

Change Detection
      ↓
Does this subtree need checking?
      ↓
   ┌──┴──┐
  No    Yes
  ↓      ↓
Skip   Check
         ↓
   Evaluate bindings
         ↓
   Update DOM if required

Key Points

  1. Angular supports Default and OnPush change-detection strategies.
  2. Default uses Angular's normal eager checking behavior.
  3. OnPush enables Angular to skip unaffected component subtrees.
  4. OnPush does not mean "Angular checks only once."
  5. OnPush does not mean "Angular checks only when @Input changes."
  6. Object and array reference changes are important with OnPush.
  7. Immutable state updates are a good practice with OnPush.
  8. Signals and OnPush work particularly well together.
  9. AsyncPipe works correctly with OnPush.
  10. Use markForCheck() when you need to explicitly mark an OnPush view for checking.

Interview Questions and Answers

1. What is ChangeDetectionStrategy.OnPush?

OnPush is an Angular change-detection strategy that allows Angular to skip a component subtree when Angular has no indication that the subtree needs checking.


2. What is the difference between Default and OnPush?

Default uses normal eager checking during change-detection traversal.

OnPush allows Angular to skip unaffected component subtrees, reducing unnecessary work.


3. Does OnPush mean Angular checks only when @Input changes?

No. That's a common misconception.

An OnPush component can also be checked because of events, Signals, AsyncPipe, markForCheck(), and other Angular notification mechanisms.


4. Why are immutable objects recommended with OnPush?

Because OnPush commonly relies on input value/reference changes. Mutating an existing object preserves its reference, whereas creating a new object provides a new reference.

// Mutation
this.user.name = 'Mohamed';

// Immutable update
this.user = {
  ...this.user,
  name: 'Mohamed'
};

5. Does OnPush work with Signals?

Yes. Signals work very well with OnPush.

count = signal(0);

count.update(x => x + 1);

When a template-consumed Signal changes, Angular knows the consuming view needs refreshing.


6. Which is faster: Default or OnPush?

OnPush can reduce change-detection work because Angular can skip unaffected component subtrees. The actual performance benefit depends on the application's component tree and update patterns.


7. Should every component use OnPush?

Not necessarily. OnPush is especially useful where predictable state flow, Signals, Observables, immutable data, or large component trees make subtree skipping beneficial.


Interview Quick Answer

Default change detection uses Angular's normal eager checking behavior, while OnPush allows Angular to skip component subtrees that do not need checking. OnPush works especially well with immutable inputs, Signals, and Observables, and can reduce unnecessary change-detection work.

← Back to Articles