I maintain over a dozen Angular applications. I generally try to keep them all up to date with the latest Angular. I do this for security, and to get the best performance and developer experience for myself.
One thing I keep seeing in the v22 ng update migrations is this line added to nearly every component:
changeDetection: ChangeDetectionStrategy.Eager,
I appreciate that Angular always ships migrations that are very likely to work, but this line has become the bane of my upgrades. Angular switched the default change detection strategy to OnPush in v22. To keep existing components working, the migration explicitly opts every component without a declared strategy into Eager, the new name for the old default. That's the safest approach. But virtually all of the code I've written over the past decade has already been OnPush-compatible (although I never bothered specifying), so now I have the extra step of going back and removing every one of these.
From a safety standpoint, I should probably retest everything, but that's laborious and complicated work. If all changes to component state flow through signals, inputs (with new references rather than in-place mutation), and template event handlers, and you aren't doing anything outside normal Angular best practices, you're already safe.
When isn't it safe to delete and switch to OnPush?
The classic case is a component that updates a plain class field from somewhere Angular doesn't know about:
@Component({
selector: 'app-clock',
template: `{{ now | date:'mediumTime' }}`,
})
export class ClockComponent {
now = new Date();
constructor() {
setInterval(() => this.now = new Date(), 1000);
}
}
Under Eager, zone.js triggers change detection after every interval tick, and the clock updates. Remove the Eager line and the component becomes OnPush. Nothing marks it dirty, so the clock freezes on the time it first rendered. The same thing happens when you assign to a plain field inside an observable subscribe(), or push() onto an input array instead of passing a new one. The fix is to make now a signal (now = signal(new Date()) and this.now.set(new Date())), at which point the line really can go.
There's a subtler case too: an Eager child inside an OnPush parent only gets checked when the parent does. So removing the line from a parent can break a child that still depends on the old behavior.
Could there be a better way for us developers? I've heard the Angular MCP has this migration as a recommendation, but maybe it should just be built into the migration at this point?






