Back to Guides

Angular Performance Optimization

Master Angular performance with lazy loading, change detection strategies, AOT compilation, and modern optimization techniques.

Angular Performance Challenges

Angular is a powerful framework, but its comprehensive nature can lead to performance bottlenecks if not configured properly. Key areas include change detection, bundle size, lazy loading, and compilation strategy. Modern Angular (v14+) includes significant performance improvements, but understanding optimization techniques is crucial.

Lazy Loading

Load modules on-demand to reduce initial bundle size.

Change Detection

Optimize Angular's change detection for better runtime performance.

AOT Compilation

Ahead-of-Time compilation for faster startup and smaller bundles.

Tree-Shaking

Remove unused code with proper imports and Ivy renderer.

1. Implement Lazy Loading

Reduce initial bundle size by loading modules only when needed:

Route-Based Lazy Loading

javascript
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module')
.then(m => m.DashboardModule)
},
{
path: 'admin',
loadChildren: () => import('./admin/admin.module')
.then(m => m.AdminModule)
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

Standalone Components (Angular 14+)

javascript
// Lazy load standalone components
const routes: Routes = [
{
path: 'dashboard',
loadComponent: () => import('./dashboard/dashboard.component')
.then(m => m.DashboardComponent)
}
];

Preloading Strategy

javascript
// Preload modules after initial load
import { PreloadAllModules } from '@angular/router';
@NgModule({
imports: [
RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
})
]
})

2. Optimize Change Detection

Angular's change detection can be expensive. Optimize it for better performance:

OnPush Change Detection Strategy

javascript
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
@Component({
selector: 'app-user-card',
templateUrl: './user-card.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserCardComponent {
@Input() user: User;
}

Manual Change Detection

javascript
import { Component, ChangeDetectorRef } from '@angular/core';
export class MyComponent {
constructor(private cdr: ChangeDetectorRef) {}
updateData(data: any) {
this.data = data;
// Manually trigger change detection
this.cdr.markForCheck();
}
// Detach from change detection for expensive operations
performExpensiveOperation() {
this.cdr.detach();
// ... expensive work
this.cdr.reattach();
}
}

TrackBy for ngFor

html
<!-- Without trackBy (slow) -->
<div *ngFor="let item of items">{{ item.name }}</div>
<!-- With trackBy (fast) -->
<div *ngFor="let item of items; trackBy: trackByFn">
{{ item.name }}
</div>
// Component
trackByFn(index: number, item: any): any {
return item.id; // unique identifier
}

3. Enable AOT Compilation

Ahead-of-Time compilation improves startup performance:

Production Build Configuration

typescript
// angular.json
{
"projects": {
"my-app": {
"architect": {
"build": {
"configurations": {
"production": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
}
}
}
}
}
}
}

Build Command

bash
# Production build with AOT
ng build --configuration=production
# Analyze bundle size
npm install -g webpack-bundle-analyzer
ng build --stats-json
webpack-bundle-analyzer dist/my-app/stats.json

4. Optimize Bundle Size

Reduce JavaScript bundle size for faster downloads:

Tree-Shakable Providers

javascript
// Use providedIn for tree-shakable services
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // Tree-shakable
})
export class MyService { }

Import Only What You Need

javascript
// Bad - imports entire module
import * as moment from 'moment';
// Good - import only what you need
import { format } from 'date-fns';
// Even better - use Angular's DatePipe
{{ date | date:'short' }}

Differential Loading

typescript
// tsconfig.json - Modern browsers get smaller bundles
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020"
}
}

5. Optimize Templates and Pipes

Improve runtime performance with template optimizations:

Pure Pipes

javascript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'exponential',
pure: true // Only recompute when input changes
})
export class ExponentialPipe implements PipeTransform {
transform(value: number, exponent = 1): number {
return Math.pow(value, exponent);
}
}

Avoid Function Calls in Templates

javascript
<!-- Bad - function called every change detection -->
<div>{{ calculateTotal() }}</div>
<!-- Good - use computed property or pipe -->
<div>{{ total }}</div>
// Component
get total() {
return this.items.reduce((sum, item) => sum + item.price, 0);
}

Use ng-container

html
<!-- Don't add extra DOM nodes -->
<ng-container *ngIf="user">
<div>{{ user.name }}</div>
<div>{{ user.email }}</div>
</ng-container>

6. Image and Asset Optimization

Optimize images with Angular's Image directive (v15+):

NgOptimizedImage

javascript
import { NgOptimizedImage } from '@angular/common';
@Component({
imports: [NgOptimizedImage],
template: `
<img
ngSrc="hero.jpg"
width="800"
height="600"
priority
alt="Hero image"
/>
`
})

Lazy Loading Images

html
<img
ngSrc="below-fold.jpg"
width="400"
height="300"
loading="lazy"
alt="Below fold image"
/>

7. Runtime Performance

Additional runtime optimizations:

  • Use Web Workers for CPU-intensive tasks
  • Implement virtual scrolling with @angular/cdk/scrolling
  • Use RxJS operators to avoid memory leaks (unsubscribe)
  • Implement service worker for offline support and caching
  • Use Angular DevTools to profile component performance

Analyze Your Angular App

Get Angular-specific optimization recommendations powered by AI.

Test Your Angular Site