← Back to Articles         
What is Route Lazy Loading in Angular?

What is Route Lazy Loading in Angular?

Published on 30 Sep 2026     7 min read Angular
Routing

What is Route Lazy Loading in Angular?

What is Route Lazy Loading?

Route lazy loading is a technique where Angular loads a component or feature only when the user navigates to its route, instead of loading everything when the application initially starts.

For example, suppose an application contains:

Home
Products
Orders
Admin
Reports

Without lazy loading:

Application starts
      ↓
Home code loaded
Products code loaded
Orders code loaded
Admin code loaded
Reports code loaded

With lazy loading:

Application starts
      ↓
Only initial required code loaded

User visits /products
      ↓
Products code loaded

User visits /admin
      ↓
Admin code loaded

This helps reduce the initial JavaScript bundle and startup work, especially in larger applications.


Full Simple Sample Program

In modern standalone Angular, a common lazy-loading approach is loadComponent().

home.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  standalone: true,
  template: `
    <h2>Home Page</h2>
    <p>Welcome to the application.</p>
  `
})
export class Home {
}

products.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-products',
  standalone: true,
  template: `
    <h2>Products Page</h2>

    <ul>
      <li>Laptop</li>
      <li>Mobile</li>
      <li>Keyboard</li>
    </ul>
  `
})
export class Products {
}

app.routes.ts

import { Routes } from '@angular/router';

import { Home } from './home';

export const routes: Routes = [
  {
    path: '',
    component: Home
  },
  {
    path: 'products',
    loadComponent: () =>
      import('./products')
        .then(m => m.Products)
  }
];

app.ts

import { Component } from '@angular/core';
import { RouterLink, RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    RouterLink,
    RouterOutlet
  ],
  template: `
    <h1>My Angular Application</h1>

    <nav>
      <a routerLink="/">Home</a> |
      <a routerLink="/products">Products</a>
    </nav>

    <hr>

    <router-outlet></router-outlet>
  `
})
export class App {
}

app.config.ts

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes)
  ]
};

main.ts

import { bootstrapApplication } from '@angular/platform-browser';

import { App } from './app/app';
import { appConfig } from './app/app.config';

bootstrapApplication(App, appConfig)
  .catch(err => console.error(err));

Explanation

The important code is:

{
  path: 'products',
  loadComponent: () =>
    import('./products')
      .then(m => m.Products)
}

Notice that we did not statically import Products at the top of app.routes.ts.

We didn't write:

import { Products } from './products';

Instead, we use dynamic import():

import('./products')

This allows the build system to split that code so it can be loaded when needed.


component vs loadComponent

Normal/Eager Route

import { Products } from './products';

{
  path: 'products',
  component: Products
}

The component is statically referenced by the route configuration.

Lazy Route

{
  path: 'products',
  loadComponent: () =>
    import('./products')
      .then(m => m.Products)
}

The component can be placed in a separate lazy-loaded chunk and fetched when that route is needed.


Lazy Loading Flow

Initially, the user opens:

/

Angular displays:

Home

The Products route has not yet been activated.

Then the user clicks:

<a routerLink="/products">Products</a>

Angular Router sees:

/products

and finds:

{
  path: 'products',
  loadComponent: ...
}

Then:

User navigates to /products
            ↓
Angular Router matches "products"
            ↓
loadComponent() executes
            ↓
import('./products')
            ↓
Lazy chunk is requested if not already loaded
            ↓
Products component becomes available
            ↓
Products displayed in <router-outlet>

Lazy Loading Multiple Routes

Suppose your application has:

/products
/orders
/admin

You could configure:

export const routes: Routes = [
  {
    path: 'products',
    loadComponent: () =>
      import('./products')
        .then(m => m.Products)
  },
  {
    path: 'orders',
    loadComponent: () =>
      import('./orders')
        .then(m => m.Orders)
  },
  {
    path: 'admin',
    loadComponent: () =>
      import('./admin')
        .then(m => m.Admin)
  }
];

Conceptually:

Initial Application
       │
       ├── /products
       │      ↓
       │  Load Products
       │
       ├── /orders
       │      ↓
       │  Load Orders
       │
       └── /admin
              ↓
          Load Admin

Lazy Loading a Group of Routes

For a larger feature, instead of lazy loading only one component, you can lazy load an entire route configuration using loadChildren.

For example:

products/
   ├── products.routes.ts
   ├── product-list.ts
   └── product-details.ts

products.routes.ts

import { Routes } from '@angular/router';

import { ProductList } from './product-list';
import { ProductDetails } from './product-details';

export const PRODUCT_ROUTES: Routes = [
  {
    path: '',
    component: ProductList
  },
  {
    path: ':id',
    component: ProductDetails
  }
];

Then in the main routes:

export const routes: Routes = [
  {
    path: 'products',
    loadChildren: () =>
      import('./products/products.routes')
        .then(m => m.PRODUCT_ROUTES)
  }
];

Now:

/products
    ↓
Lazy load PRODUCT_ROUTES
    ↓
ProductList


/products/10
    ↓
Lazy load PRODUCT_ROUTES
    ↓
ProductDetails

This is very useful for large feature areas.


loadComponent() vs loadChildren()

loadComponent() loadChildren()
Lazy loads a component Lazy loads a route configuration / feature
Good for a single page Good for multiple related routes
Common with standalone components Common for feature route groups
Simple route Larger feature area

Example

Single page:

{
  path: 'about',
  loadComponent: () =>
    import('./about')
      .then(m => m.About)
}

Feature containing several pages:

{
  path: 'products',
  loadChildren: () =>
    import('./products/products.routes')
      .then(m => m.PRODUCT_ROUTES)
}

How Was Lazy Loading Done Before Standalone Angular?

In traditional NgModule-based Angular, lazy loading commonly loaded a feature module.

For example:

{
  path: 'products',
  loadChildren: () =>
    import('./products/products.module')
      .then(m => m.ProductsModule)
}

The feature module could then import its routing module:

@NgModule({
  imports: [
    CommonModule,
    ProductsRoutingModule
  ]
})
export class ProductsModule {
}

And ProductsRoutingModule used:

RouterModule.forChild(routes)

So the traditional structure was:

AppRoutingModule
      ↓
loadChildren()
      ↓
ProductsModule
      ↓
ProductsRoutingModule
      ↓
RouterModule.forChild()

Modern standalone Angular can avoid creating feature NgModules just for this purpose.


Eager Loading vs Lazy Loading

Eager Loading Lazy Loading
Code is part of the initially reachable/static dependency graph Code is split so it can be loaded when needed
Larger initial bundle/work if many features are eager Can reduce initial bundle/work
Simple for small apps Very useful for large apps
component: with static import loadComponent: / loadChildren: with dynamic import

For example:

Eager

import { Products } from './products';

{
  path: 'products',
  component: Products
}

Lazy

{
  path: 'products',
  loadComponent: () =>
    import('./products')
      .then(m => m.Products)
}

Advantages of Lazy Loading

1. Smaller initial bundle

The browser doesn't need to download every feature immediately.

2. Faster initial startup potential

Less initial JavaScript can mean less download, parsing, and execution work.

3. Better for large applications

Features such as:

Admin
Reports
Orders
Settings

may not be needed by every user immediately.

4. Feature-oriented structure

Large sections of an application can be separated into their own route configurations.


Key Points

  • Lazy loading means loading route-related code when needed instead of eagerly at application startup.
  • Standalone components can be lazy loaded with:
loadComponent
  • Example:
{
  path: 'products',
  loadComponent: () =>
    import('./products')
      .then(m => m.Products)
}
  • Groups of routes can be lazy loaded using:
loadChildren
  • Example:
{
  path: 'products',
  loadChildren: () =>
    import('./products/products.routes')
      .then(m => m.PRODUCT_ROUTES)
}
  • Lazy loading can reduce the application's initial JavaScript payload.
  • Dynamic import() enables code splitting for lazy routes.
  • Older NgModule-based applications commonly used loadChildren() to lazy load feature modules.

Interview Questions and Answers

1. What is route lazy loading in Angular?

Route lazy loading is a technique where Angular loads the code for a component or feature only when its route is needed, rather than including all feature code in the initial application load.


2. How do you lazy load a standalone component?

Use loadComponent():

{
  path: 'products',
  loadComponent: () =>
    import('./products')
      .then(m => m.Products)
}

3. What is loadChildren()?

loadChildren() lazy loads a set of routes or, in older NgModule-based applications, a feature module.

Modern example:

{
  path: 'products',
  loadChildren: () =>
    import('./products/products.routes')
      .then(m => m.PRODUCT_ROUTES)
}

4. What is the difference between loadComponent() and loadChildren()?

loadComponent() lazy loads an individual component, while loadChildren() is used to lazy load a group of routes or an NgModule-based feature.


5. Why do we use lazy loading?

The main reason is to reduce the initial amount of JavaScript that must be loaded and processed, which can improve startup performance in larger applications.


6. How was lazy loading implemented before standalone Angular?

NgModule-based applications commonly lazy loaded feature modules:

{
  path: 'products',
  loadChildren: () =>
    import('./products/products.module')
      .then(m => m.ProductsModule)
}

The feature module's routing typically used:

RouterModule.forChild(routes)

Interview-ready answer

Route lazy loading in Angular means loading the code for a route only when that route is needed. In modern standalone Angular, loadComponent() can lazy load an individual standalone component, while loadChildren() can lazy load a group of routes. Lazy loading reduces the initial JavaScript payload and is especially useful for large applications with features such as Admin, Reports, and Orders.

← Back to Articles