Skip to content

Angular Lazy Loading

Lazy loading splits your application into smaller chunks that download only when needed, dramatically improving initial load time for larger apps. This lesson covers how to configure it with the router.

What Is Lazy Loading?

By default, everything imported eagerly ends up in the application's main JavaScript bundle, downloaded before the user sees anything. Lazy loading defers loading a route's code until the user actually navigates to it, splitting that code into a separate chunk fetched on demand.

This matters most for large applications with many features that not every user visits in a given session, an admin panel, a rarely used settings page, or a large reporting module.

export const routes: Routes = [
  { path: '', component: HomeComponent }, // eager, part of the main bundle
  {
    path: 'reports',
    loadChildren: () => import('./reports/reports.routes').then(m => m.REPORTS_ROUTES),
  }, // lazy, its own chunk
];

Visiting any URL other than /reports/... never downloads the reports feature's code at all.

Lazy Loading Syntax

{ path: 'x', loadComponent: () => import('./x.component').then(m => m.XComponent) }
{ path: 'y', loadChildren: () => import('./y.routes').then(m => m.Y_ROUTES) }
  • loadComponent lazily loads a single standalone component for a single route.
  • loadChildren lazily loads an entire feature's route configuration (potentially many routes) at once.
  • Both use the dynamic import() syntax, which the build tooling automatically recognizes as a code-split boundary.
  • Lazy-loaded routes can define their own scoped providers, isolated from the rest of the app.

Lazy Loading Cheatsheet

Key patterns for configuring and verifying lazy-loaded routes.

Task Example
Lazy load one component loadComponent: () => import('./x.component').then(m => m.X)
Lazy load a feature's routes loadChildren: () => import('./feature.routes')
Route-scoped providers providers: [FeatureOnlyService] on the lazy route
Preloading strategy withPreloading(PreloadAllModules) in provideRouter()
Analyze bundle chunks ng build --stats-json + a bundle visualizer

Why Lazy Loading Matters for Performance

The initial bundle a user downloads directly affects how quickly your app becomes interactive. Splitting rarely-visited features into separate chunks means users pay that download cost only if (and when) they actually navigate there, rather than upfront for everyone.

Lazy Loading an Entire Feature

For a feature with several related routes, loadChildren pointing at a routes file (rather than a single component) keeps the whole feature, and all of its own nested routes, in one lazily-loaded chunk.

// reports.routes.ts
export const REPORTS_ROUTES: Routes = [
  { path: '', component: ReportsOverviewComponent },
  { path: ':id', component: ReportDetailComponent },
];

// app.routes.ts
{ path: 'reports', loadChildren: () => import('./reports/reports.routes').then(m => m.REPORTS_ROUTES) }

Preloading Lazy Chunks in the Background

Lazy loading doesn't have to mean waiting until the exact moment of navigation, a preloading strategy can fetch lazy chunks in the background after the initial page finishes loading, trading a little extra bandwidth for a faster subsequent navigation.

provideRouter(routes, withPreloading(PreloadAllModules))

Common Mistakes

  • Lazy loading small, frequently-visited routes where the extra network round-trip outweighs any bundle-size benefit.
  • Forgetting to verify the actual bundle output, assuming a route is lazy without confirming it's really split into its own chunk.
  • Importing a lazily-loaded feature's component eagerly elsewhere in the app, defeating the purpose of the split.
  • Not considering a preloading strategy for a small app where eagerly loading everything upfront may already be fast enough.

Key Takeaways

  • Lazy loading defers downloading a route's code until it's actually needed, reducing initial bundle size.
  • loadComponent lazily loads a single component; loadChildren lazily loads a whole feature's routes.
  • Preloading strategies can fetch lazy chunks in the background after the initial page load.
  • Always verify lazy loading is working with real build output analysis, not just by reading the route configuration.

Pro Tip

Run ng build and inspect the generated chunk files (or use a bundle analyzer) to confirm a lazily-loaded route actually produced a separate JavaScript file, it's easy to accidentally defeat lazy loading with an unrelated eager import elsewhere.