Lazy Loading in Angular
What is Lazy Loading?
Lazy loading is a design pattern that defers the loading of a module or component until it is actually needed. Instead of loading the entire application upfront, Angular splits the code into separate bundles and loads each bundle only when the user navigates to that route. This dramatically improves initial load time and reduces the initial bundle size.
Lazy Loading Routes (Angular 21)
In Angular 21 with standalone components, lazy loading is done using loadComponent for a single component or loadChildren for a group of routes. The dynamic import() syntax tells the bundler to create a separate chunk.
import { Routes } from '@angular/router';
export const routes: Routes = [
// Eagerly loaded — always in the main bundle
{ path: '', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent) },
// Lazy loaded single component — separate chunk
{
path: 'about',
loadComponent: () => import('./about/about.component').then(m => m.AboutComponent)
},
// Lazy loaded feature module (group of routes) — separate chunk
{
path: 'admin',
loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes)
},
// Lazy loaded with route guard
{
path: 'dashboard',
loadComponent: () => import('./dashboard/dashboard.component').then(m => m.DashboardComponent),
canActivate: [authGuard]
}
];
// admin/admin.routes.ts — loaded only when user visits /admin
import { Routes } from '@angular/router';
export const adminRoutes: Routes = [
{
path: '',
loadComponent: () => import('./admin-home/admin-home.component').then(m => m.AdminHomeComponent)
},
{
path: 'users',
loadComponent: () => import('./users/users.component').then(m => m.UsersComponent)
},
{
path: 'settings',
loadComponent: () => import('./settings/settings.component').then(m => m.SettingsComponent)
}
];
@defer — Template-level Lazy Loading (Angular 17+)
Angular 17 introduced the @defer block for lazy loading components directly in templates. Unlike route-based lazy loading, @defer works at the component level and supports multiple trigger conditions.
import { Component } from '@angular/core';
import { HeavyChartComponent } from './heavy-chart.component';
import { CommentSectionComponent } from './comment-section.component';
@Component({
selector: 'app-page',
standalone: true,
template: `
<h1>Article Title</h1>
<p>Article content...</p>
<!-- Load chart only when it enters the viewport -->
@defer (on viewport) {
<app-heavy-chart />
} @loading {
<p>Loading chart...</p>
} @placeholder {
<div class="chart-placeholder">Chart will appear here</div>
} @error {
<p>Failed to load chart.</p>
}
<!-- Load comments only on user interaction -->
@defer (on interaction) {
<app-comment-section />
} @placeholder {
<button>Load Comments</button>
}
<!-- Load after 2 seconds idle time -->
@defer (on idle; prefetch on immediate) {
<app-recommendations />
}
`
})
export class PageComponent {}
Preloading Strategies
By default, lazy-loaded modules are only fetched when the user navigates to them. Angular provides preloading strategies to load lazy modules in the background after the initial load, so they are ready when needed.
| Strategy | Behaviour | Best for |
|---|---|---|
NoPreloading (default) | Load only on navigation | Bandwidth-sensitive apps |
PreloadAllModules | Preload all lazy modules after initial load | Small to medium apps |
| Custom strategy | Preload only routes with a specific flag | Large apps with selective preloading |
import { ApplicationConfig } from '@angular/core';
import { provideRouter, withPreloading, PreloadAllModules } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(
routes,
withPreloading(PreloadAllModules) // preload all lazy modules in background
)
]
};
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.