Skip to content

Angular Performance

Angular applications can stay fast even as they grow, if you apply the right techniques deliberately. This lesson brings together the most impactful performance practices covered throughout this course.

Where Angular Performance Problems Usually Come From

Most real-world Angular performance issues fall into a few recognizable categories: too much work done on every change detection cycle, an oversized initial bundle, inefficient list rendering, and rendering huge lists entirely instead of only what's visible.

Addressing each category has a specific, well-established technique, there's rarely a need to guess; measure first, then apply the matching fix.

// Before: default change detection, mutated arrays, no tracking
<li *ngFor="let item of items">{{ item.name }}</li>

// After: OnPush component + track by id
@Component({ changeDetection: ChangeDetectionStrategy.OnPush })
// template:
@for (item of items; track item.id) {
  <li>{{ item.name }}</li>
}

Combining OnPush with proper list tracking addresses two of the most common sources of unnecessary work simultaneously.

The Performance Technique Toolkit

ChangeDetectionStrategy.OnPush + signals   // reduce unnecessary checks
loadComponent / loadChildren                // reduce initial bundle size
track (in @for) / trackBy (in *ngFor)         // efficient list reconciliation
pure pipes (default)                          // avoid recomputation on every check
CdkVirtualScrollViewport                      // render only visible list items
  • OnPush and signals reduce how much change detection work Angular does per cycle.
  • Lazy loading reduces how much JavaScript users download before they can interact with the app.
  • track/trackBy avoid unnecessary DOM node recreation when list data changes.
  • Virtual scrolling renders only the list items currently visible in the viewport, not the entire list at once.

Angular Performance Cheatsheet

Techniques mapped to the problem they solve.

Problem Technique
Too much change detection work OnPush strategy + signals
Large initial bundle loadComponent/loadChildren lazy loading
Inefficient list re-renders track/trackBy in @for/*ngFor
Expensive repeated computations Pure pipes or computed() signals (memoized)
Rendering huge lists CdkVirtualScrollViewport (virtual scrolling)
Slow initial paint for public pages Server-side rendering / prerendering
Unused code shipped to the browser Bundle analysis + removing unused imports/dependencies

Measure Before Optimizing

Angular DevTools' profiler (a browser extension) shows exactly which components are checked and how long each check takes, letting you target real bottlenecks instead of guessing. Chrome DevTools' Performance tab and Lighthouse cover broader page-level metrics like load time and interactivity.

Virtual Scrolling for Large Lists

Rendering thousands of DOM nodes for a long list is expensive, even with perfect change detection. The Component Dev Kit's (@angular/cdk) CdkVirtualScrollViewport renders only the items currently visible (plus a small buffer), recycling DOM nodes as the user scrolls.

<cdk-virtual-scroll-viewport itemSize="48" class="viewport">
  <div *cdkVirtualFor="let item of items">{{ item.name }}</div>
</cdk-virtual-scroll-viewport>

Analyzing and Reducing Bundle Size

Build output stats reveal which dependencies contribute the most to bundle size, sometimes surfacing an unexpectedly large library pulled in for a small feature, or an eagerly-loaded route that should be lazy instead.

ng build --stats-json
npx webpack-bundle-analyzer dist/my-app/stats.json

Avoiding Expensive Template Expressions

A method call directly in a template expression ({{ getTotal() }}) re-runs on every check, potentially very often. Replacing it with a computed() signal (or a pure pipe) ensures the expensive work only re-runs when its actual inputs change.

Common Mistakes

  • Optimizing based on guesses instead of profiling with Angular DevTools or browser performance tools first.
  • Calling expensive methods directly in template interpolation instead of using computed() or a pure pipe.
  • Rendering very large lists without virtual scrolling, even after applying OnPush and track.
  • Shipping large third-party dependencies for a small feature without checking their bundle size impact first.

Key Takeaways

  • Most Angular performance problems fall into a few well-known categories, each with an established fix.
  • Profile first with Angular DevTools and browser performance tools before optimizing.
  • OnPush, signals, track, and lazy loading address the most common sources of wasted work.
  • Virtual scrolling and bundle analysis handle large-list rendering and oversized bundles specifically.

Pro Tip

Install the Angular DevTools browser extension and use its component profiler before making any performance change, it will show you exactly which components are being checked unnecessarily, turning guesswork into a targeted fix.