Lazy Loading Feature Routes
As an Angular application grows, bundling every feature into a single JavaScript file means users pay the download and parse cost of code they may never visit — an admin panel, a settings page, a rarely-used reporting module. Lazy loading solves this by splitting the application into smaller chunks that the build tooling (esbuild, via the Angular CLI) emits as separate files, which the router then fetches over the network only when the user actually navigates to a route that needs them. This is one of the highest-leverage performance techniques available in Angular and requires no manual bundler configuration — it's driven entirely by how routes are declared.
Cricket analogy: Bundling every feature into one file is like a broadcaster shipping every camera angle from every ground worldwide in one feed even though a viewer only watches the Lord's Test; lazy loading only streams the one match the fan actually tunes into.
loadComponent for Standalone Components
For a single standalone component, lazy loading is expressed with loadComponent, a function returning a dynamic import() that resolves to the component class. The Angular CLI's build system automatically detects the dynamic import() call and generates a separate chunk for it. This replaces the pre-standalone pattern of lazy-loading an entire NgModule via loadChildren, which required wrapping even a single component in a dedicated feature module just to defer it.
Cricket analogy: loadComponent for a single standalone component is like fielding a specialist death-bowler brought on only for the final over, resolved via a dynamic call the moment he's needed, replacing the older approach of keeping an entire reserve squad (NgModule) on standby just to field one player.
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent) },
{
path: 'settings',
loadComponent: () => import('./settings/settings.component').then(m => m.SettingsComponent),
title: 'Settings',
},
];loadChildren for Grouped Feature Routes
When a whole feature area has multiple related routes (e.g. an admin section with a dashboard, users list, and settings page), it's cleaner to lazy-load a nested Routes array in one chunk using loadChildren. The child file exports its own Routes array, and the parent route's path acts as a prefix for every child path. This groups related code into one network request instead of many small ones, and keeps the parent routing file uncluttered.
Cricket analogy: Lazy-loading a nested Routes array with loadChildren for an admin section is like chartering one team bus that carries the captain, coach, and physio together for an away series, instead of booking three separate flights, with the tour's base city acting as the prefix for every fixture on that leg.
// app.routes.ts
export const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES),
canActivate: [authGuard], // guards on the parent route protect all children
},
];
// admin/admin.routes.ts
import { Routes } from '@angular/router';
export const ADMIN_ROUTES: Routes = [
{ path: '', loadComponent: () => import('./admin-dashboard.component').then(m => m.AdminDashboardComponent) },
{ path: 'users', loadComponent: () => import('./admin-users.component').then(m => m.AdminUsersComponent) },
];Angular's provideRouter() also accepts withPreloading(PreloadAllModules) (or a custom PreloadingStrategy), which fetches lazy chunks in the background after the initial page finishes loading, so subsequent navigations feel instant while the first paint still stays fast — a middle ground between eager loading everything and loading strictly on demand.
A common mistake is importing a lazily-loaded component's class directly elsewhere in eagerly-loaded code (e.g. adding it to another component's imports array). This creates a static reference that bundlers can trace, pulling the 'lazy' chunk back into the main bundle and silently defeating the code-splitting entirely.
- Lazy loading splits the app into separate JS chunks fetched only when a route is visited, shrinking the initial bundle.
loadComponentlazily loads a single standalone component via a dynamic import().loadChildrenlazily loads a nestedRoutesarray for a whole feature area, grouping related routes into one chunk.- Guards placed on the parent route (e.g. canActivate) apply to all of its lazily-loaded children.
withPreloading(PreloadAllModules)fetches lazy chunks in the background after initial load for faster subsequent navigation.- Avoid eagerly importing a lazy component's class elsewhere, which silently merges it back into the main bundle.
Practice what you learned
1. Which route property lazy-loads a single standalone component?
2. What is the primary use case for `loadChildren` over `loadComponent`?
3. If a canActivate guard is set on a parent route that uses loadChildren, what happens to its child routes?
4. What does `withPreloading(PreloadAllModules)` do?
5. What mistake commonly defeats lazy loading for a component?
Was this page helpful?
You May Also Like
Angular Router Basics
Learn how Angular's built-in router maps URL paths to components, enabling single-page applications to feel like multi-page sites without full page reloads.
Route Guards
Learn how functional route guards control navigation access — protecting routes behind authentication, confirming unsaved changes, and pre-fetching data before activation.
Standalone Components and Bootstrapping
Understand how standalone components eliminate the need for NgModules, and how modern Angular applications bootstrap directly from a root component and providers array.
Building and Deploying an Angular App
Learn how ng build produces an optimized production bundle, what build configurations and budgets control, and common strategies for deploying an Angular app to a live environment.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics