All topics
Routingintermediate

Lazy Loading with loadComponent and loadChildren

Explain how lazy loading defers a feature's code until its route is visited, reducing initial bundle size.

Every eagerly imported component, service, and module adds to the JavaScript the browser must download, parse, and execute before the app becomes interactive — and most users of any given feature-rich application only ever visit a fraction of its total routes in a single session. Lazy loading defers a route's code until the moment the user actually navigates to it, which is one of the highest-leverage, lowest-effort performance techniques available in Angular, and a near-guaranteed interview question in any performance-focused discussion.

It's like a streaming service that doesn't download an entire TV series to your device up front — it fetches each episode only when you actually press play on it, saving bandwidth for episodes you might never watch.

Key Concepts

1
loadComponent (for a single standalone component) and loadChildren (for a set of routes, typically exported from a feature's own routes file) both accept a dynamic import() expression, which webpack/esbuild recognizes as a code-splitting boundary — the imported module is placed into its own separate bundle chunk, only fetched over the network when that route is actually navigated to.
loadComponentloadChildrenimport()
2
This replaces the older NgModule-based lazy loading pattern (loadChildren: () => import('./feature.module').then(m => m.FeatureModule)), which required an entire lazy-loaded NgModule per feature; with standalone components, loadComponent can lazy-load a single component directly, and loadChildren can point straight at an exported Routes array with no wrapping module needed at all — a meaningfully simpler mental model.
loadChildren: () => import('./feature.module').then(m => m.FeatureModule)NgModuleloadComponentloadChildrenRoutes
3
A thorough interview answer also connects lazy loading to preloading strategies (loading lazy chunks in the background after the initial app loads, trading a bit of unnecessary bandwidth for faster subsequent navigations) and to the fact that lazy-loaded feature areas get their own child injector, which is directly relevant to the providedIn: 'any' behavior discussed under providedIn Strategies.
providedIn: 'any'