Performance — OnPush, Signals & Beyond

Surgical Re-Renders, Smaller Bundles

Performance — OnPush, Signals & Beyond

The big performance wins in modern Angular: OnPush change detection, signals, trackBy in @for, lazy loading, and preloading strategies.

5 min read Level 3/5 #angular#performance#onpush
What you'll learn
  • Switch a component to OnPush change detection
  • Use track in @for to avoid unnecessary DOM churn
  • Pick a router PreloadingStrategy

A few high-leverage knobs cover most Angular perf wins. Set them once and the framework does the rest.

OnPush + Signals

Default change detection re-checks every component on every event. OnPush only re-checks when inputs change or a signal it reads updates — usually a 10x speedup on large pages.

import { Component, ChangeDetectionStrategy, signal } from '@angular/core';

@Component({
  selector: 'app-cart',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<p>Total: {{ total() }}</p>`,
})
export class CartComponent {
  total = signal(0);
}

New components should default to OnPush + signals. Treat the default strategy as legacy.

Track in @for

Without a key, Angular has to re-create every DOM node when the list changes. track lets it diff by identity.

@for (user of users(); track user.id) {
  <li>{{ user.name }}</li>
}

Use a stable, unique value — usually an id. $index works for static lists but loses the benefit when items move.

Lazy and Preloaded Routes

Split your app at route boundaries with loadComponent, then preload them in the background so navigation feels instant.

import { provideRouter, withPreloading, PreloadAllModules } from '@angular/router';

export const appConfig = {
  providers: [
    provideRouter(routes, withPreloading(PreloadAllModules)),
  ],
};

Measure the Bundle

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

The analyzer’s treemap shows you exactly which dependency is fat. Common offenders: full moment.js, lodash, all of RxJS. Swap them for tree-shakable equivalents (date-fns, lodash-es, specific RxJS operators).

@defer — Deferred Views →