Change Detection is one of Angular’s core mechanisms. However, when your app grows, this system can sometimes cause slow rendering, UI lag, poor scrolling performance, and delayed user interactions. The good news? These issues are fixable with a few smart optimizations.
This guide explains why Angular apps become slow, how Change Detection works, and how to fix performance bottlenecks effectively.
🔍 1. Why Angular Change Detection Becomes Slow
Angular uses a mechanism that checks component values whenever something may have changed.
Your app slows down if:
- Too many components re-render unnecessarily
- Large lists are rendered without
trackBy - Heavy logic runs during change detection
- Deep component trees run in default Change Detection mode
- Multiple async streams trigger too many updates
- Excessive DOM bindings cause extra work
Understanding the root cause is the first step toward fixing the issue.
⚙️ 2. Switch to OnPush Change Detection
By default, Angular runs Change Detection on every component, every time an event happens.
Changing the strategy to OnPush significantly reduces unnecessary recalculations.
✔ How to enable OnPush:
import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserListComponent {}
📌 Benefits:
- Only re-renders when inputs change
- Boosts performance across large apps
- Prevents cascading updates
📋 *3. Use trackBy in ngFor Lists
Rendering long lists without trackBy causes Angular to re-render the entire list.
❌ Without trackBy (very slow)
<li *ngFor="let user of users">
{{ user.name }}
</li>
✔ With trackBy (super fast)
<li *ngFor="let user of users; trackBy: trackByUserId">
{{ user.name }}
</li>
trackByUserId(index: number, user: any) {
return user.id;
}
This tells Angular exactly which items changed, preventing unnecessary DOM work.
🧠 4. Avoid Heavy Computations in Templates
This is a silent killer!
❌ Bad practice:
<p>{{ calculateTotal() }}</p>
✔ Good practice:
total = this.calculateTotal();
<p>{{ total }}</p>
Never run expensive logic inside templates — Angular executes it many times per second.
🌐 5. Debounce High-Frequency Events
Some events like:
scrollmousemovekeyupinput
…can fire hundreds of times, triggering excessive Change Detection.
✔ Use RxJS debounce:
fromEvent(input, 'input')
.pipe(debounceTime(300))
.subscribe(...)
Results:
- Smoother UI
- Fewer renders
- Lower CPU usage
🧵 6. Use Signals or Observables to Control Updates (Angular 16+)
Signals and Observables with OnPush allow you to control exactly what updates the UI.
Example with Signals:
count = signal(0);
increment() {
this.count.update(v => v + 1);
}
Signals update only when changed — improving rendering efficiency.
🧼 7. Clean Up Subscriptions
Forgotten subscriptions cause:
- Memory leaks
- Re-renders
- Extra function calls
✔ Use takeUntil or async pipe:
<p>{{ user$ | async }}</p>
No manual unsubscribe needed!
🛠 8. Use Angular DevTools to Detect Slow Zones
Angular DevTools helps identify:
- Components triggering too many checks
- Large templates
- Slow change detection cycles
Check “Profiler” to find slow components instantly.
✅ Conclusion
Fixing slow Change Detection in Angular isn’t difficult — you just need to:
- Use
OnPush - Add
trackBy - Avoid expensive template logic
- Clean up subscriptions
- Optimize reactive flows
- Use Angular DevTools
Following these steps can drastically improve performance and user experience.
Citations
Internal: https://savanka.com/category/savanka-helps/
External: http://angular.dev/