Medium15 minAngular Fundamentals
UpdatedAug 2, 2026
Edit

Change Detection: Default vs. OnPush

CONCEPTS:Angular Change Detection

Why This Is Asked

Performance optimization is a key skill for senior Angular developers. Understanding how to reduce the number of change detection cycles using OnPush is essential for building scalable, high-performance applications. Interviewers want to see if you understand the triggers for change detection and how to manually manage it when necessary.

Key Concepts

  • Directed Acyclic Graph (DAG): Angular’s component tree is checked from top to bottom.
  • Immutability: OnPush relies on object reference changes.
  • ChangeDetectorRef: Manually triggering detection via markForCheck() or detectChanges().
  • Async Pipe: How it interacts with OnPush to automatically trigger updates.

Answers by Technology

+ Add Variant
AngularImprove this answer ✏️

Expected Answer

Angular provides two strategies for change detection:

1. Default Strategy

Angular checks the component and its entire child subtree whenever any asynchronous event occurs (click, timer, HTTP response) that is tracked by Zone.js. This is simple but can become a performance bottleneck in large applications as the tree grows.

2. OnPush Strategy

Angular only checks the component if:

  • One of its Input properties receives a new reference (immutability is key).
  • An event originates from the component or its children (e.g., a button click).
  • An Observable linked via the async pipe emits a new value.
  • You manually call cdr.markForCheck().

Comparison Table

Feature Default OnPush
Check frequency Every event Optimized / Selective
Performance Lower (in large apps) High
Data Requirements Mutable or Immutable Strictly Immutable (or Signals)
Complexity Low Moderate

Why It Matters

Using OnPush significantly reduces the work Angular has to do. In a complex dashboard with hundreds of components, using the Default strategy might lead to “jank” or laggy interactions because moving a mouse or typing could trigger hundreds of unnecessary checks. OnPush ensures that only the relevant branches of the component tree are updated.

Example Code

Implementing OnPush

Note that the user object must be replaced with a new reference for the change to be detected.

@Component({
  selector: 'app-user-profile',
  standalone: true,
  template: `<div>{{ user().name }}</div>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserProfileComponent {
  user = input.required<{name: string}>();
}

Common Mistakes

  • Mutating objects with OnPush: Updating user.name = 'New Name' won’t trigger change detection because the object reference remains the same.
  • Forgetting the Async Pipe: If you subscribe manually in a component with OnPush, you must call ChangeDetectorRef.markForCheck() manually inside the subscription, or Angular won’t update the UI.
  • Overusing detectChanges(): This runs change detection immediately and synchronously. Usually, markForCheck() is preferred as it marks the path for the next scheduled cycle, which is more efficient.

Follow-up Questions

  • How do Signals change this? (Answer: Signals provide fine-grained reactivity that allows Angular to update specific parts of the template even more efficiently than OnPush).
  • What causes “ExpressionChangedAfterItHasBeenCheckedError”? (Answer: Changing a property that is used in a template after Angular has already checked that component in the current cycle).
  • Does OnPush affect child components? (Answer: Yes, if a parent is skipped, its entire subtree is also skipped).

References