Angular’s OnPush strategy lets change detection skip a component subtree when Angular has no relevant reason to check it. The subtree is checked when it receives a changed template-bound input, handles an event within its scope, or is otherwise marked for checking. Since Angular v22, OnPush is the default strategy; behavior differs in older versions.
What skipping a component subtree means
Change detection traverses the component tree, but it does not need to check every component on every run. An OnPush component gives Angular permission to skip that component and its descendants when the subtree has not received a relevant update. It is conditional traversal, not permanent detachment: when a trigger marks the subtree for checking, Angular checks it.
Angular’s guide describes the rule this way: “Angular will skip descendant component subtrees with roots using OnPush, which have not received new inputs.” Angular’s subtree-skipping guide explains how inputs and events affect that traversal.
When Angular checks an OnPush subtree
A template binding passes a changed input
When a parent passes an input to an OnPush child through a template binding, Angular compares the current and previous values using Object.is. If the value differs, Angular checks the receiving child. A separate OnPush descendant can still be skipped if it has no changed input of its own.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall#1 Best Overall
For objects and arrays, that comparison is about identity. Mutating a property while passing the same object reference does not satisfy the changed-input condition. Creating and passing a new object reference does. This makes immutable-style updates a practical way to ensure input changes are observable to Angular; OnPush does not enforce immutability.
An event is handled inside the subtree
Events affect which parts of the tree Angular checks. When an event is handled inside an OnPush component, Angular checks the relevant tree, including the event component’s ancestors. Unrelated OnPush branches outside the event’s scope can remain skipped if they have no new inputs.
Rank #2
If an event is handled by a descendant, its ancestors are checked as well. If an event occurs in a component using eager change detection, Angular traverses the tree but can still skip descendant OnPush subtrees that have not received new inputs.
Another mechanism marks the component for checking
Not every update comes through a template-bound input or a local event. Angular can also be asked to check a component through mechanisms such as ChangeDetectorRef.markForCheck(). This is useful when an update occurs through an imperative reference rather than the normal template-binding flow.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
Signals and OnPush templates
When an OnPush component’s template reads a signal, Angular tracks that signal as a dependency. When the signal’s value changes, Angular marks the component so it can be checked in a later change-detection run. See the Angular signals guide.
A readonly signal prevents callers from setting its value through that signal, but it does not prevent deep mutation of an object held inside it. As with inputs, updates need to be observable to Angular; changing a nested property in place is not the same as publishing a changed signal value.
Rank #4
Why an OnPush view can look stale
When a view does not reflect an update, work through the update path rather than assuming Angular has detached the component:
- Check object identity: Did the parent mutate an object or array but pass the same reference? If so, the input comparison may not trigger a check.
- Check how the input changed: Was it passed through a template binding, or assigned imperatively through a
ViewChildorContentChildreference? An imperative assignment does not automatically check anOnPushcomponent. - Check the event scope: Did Angular handle an event inside the subtree, or did the update happen elsewhere without marking this component?
- Check signal usage: Does the template read the signal that changed, and was its value updated in a way Angular can observe?
For an imperative input change that needs to be reflected, call ChangeDetectorRef.markForCheck() so Angular can include the component in a future check. The official guide to skipping subtrees covers this case.
OnPush and Eager in current Angular
The current API lists OnPush and Eager as the change-detection strategies. OnPush allows Angular to skip a subtree until a relevant update marks it for checking; Eager components are checked eagerly when change-detection traversal reaches them. Default remains a deprecated alias for Eager in the current API and is due for removal. Consult the ChangeDetectionStrategy API reference for the current definitions.
Version matters: Angular’s current guide says OnPush has been the default since v22. If you maintain an older application, check the API documentation for that Angular version rather than assuming the current default or enum values apply.
Does skipping guarantee a performance improvement?
No universal speedup or percentage is established for OnPush. It is a runtime option for finer control over change detection, and its value depends on the application’s component tree, update patterns, and work performed during checks. Angular recommends profiling to locate actual bottlenecks; its performance guide identifies Angular DevTools as a way to inspect the component tree and profile an application.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




