What is Lazy Loading in Angular?
1. What is Lazy Loading?
Lazy loading is a technique where Angular loads a feature, component, or route only when the user needs or navigates to it, instead of loading everything when the application starts.
In simple terms:
Lazy Loading = Load it when needed, not at application startup.
For example, suppose an application has these pages:
Home
Products
Orders
Admin
Reports
Without lazy loading:
Application Starts
↓
Load Home
Load Products
Load Orders
Load Admin
Load Reports
↓
Application Ready
With lazy loading:
Application Starts
↓
Load Home only
User clicks Products
↓
Load Products
User clicks Admin
↓
Load Admin
This reduces the initial JavaScript bundle that the browser must download and process.
2. Full Simple Sample Program
In modern standalone Angular, loadComponent() is commonly used to lazy-load a standalone component.
Project structure
src/app/
│
├── app.ts
├── app.html
├── app.routes.ts
│
├── home/
│ ├── home.ts
│ └── home.html
│
├── products/
│ ├── products.ts
│ └── products.html
│
└── admin/
├── admin.ts
└── admin.html
app.routes.ts
import { Routes } from '@angular/router';
import { Home } from './home/home';
export const routes: Routes = [
{
path: '',
component: Home
},
{
path: 'products',
loadComponent: () =>
import('./products/products')
.then(m => m.Products)
},
{
path: 'admin',
loadComponent: () =>
import('./admin/admin')
.then(m => m.Admin)
}
];
app.ts
import { Component } from '@angular/core';
import { RouterLink, RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterLink, RouterOutlet],
templateUrl: './app.html'
})
export class App {
}
app.html
<h1>My Angular Application</h1>
<nav>
<a routerLink="/">Home</a> |
<a routerLink="/products">Products</a> |
<a routerLink="/admin">Admin</a>
</nav>
<hr>
<router-outlet></router-outlet>
home/home.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
standalone: true,
templateUrl: './home.html'
})
export class Home {
}
home/home.html
<h2>Home</h2>
<p>Welcome to the application.</p>
products/products.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-products',
standalone: true,
templateUrl: './products.html'
})
export class Products {
}
products/products.html
<h2>Products</h2>
<p>Products page loaded successfully.</p>
admin/admin.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-admin',
standalone: true,
templateUrl: './admin.html'
})
export class Admin {
}
admin/admin.html
<h2>Admin</h2>
<p>Admin page loaded successfully.</p>
3. Explanation
The important code is:
{
path: 'products',
loadComponent: () =>
import('./products/products')
.then(m => m.Products)
}
Notice that we didn't import Products at the top of app.routes.ts.
We did not write:
import { Products } from './products/products';
Instead, Angular uses dynamic import():
import('./products/products')
This tells the bundler that the Products feature can be split into a separate chunk.
When the user navigates to:
/products
Angular loads that chunk and then uses:
.then(m => m.Products)
to retrieve the Products component.
4. Normal Loading vs Lazy Loading
Eager loading
import { Products } from './products/products';
export const routes: Routes = [
{
path: 'products',
component: Products
}
];
Here, Products is statically imported and is part of the application's eagerly reachable code.
Conceptually:
Application starts
↓
Main application code
+
Products
↓
Application runs
Lazy loading
{
path: 'products',
loadComponent: () =>
import('./products/products')
.then(m => m.Products)
}
Conceptually:
Application starts
↓
Initial application code
Later...
User → /products
↓
Products chunk downloaded
↓
Products component displayed
5. loadComponent() vs loadChildren()
There are two important lazy-loading mechanisms in Angular routing.
loadComponent()
Used to lazy-load a standalone component.
{
path: 'products',
loadComponent: () =>
import('./products/products')
.then(m => m.Products)
}
This is ideal for a single standalone route component.
loadChildren()
Used to lazy-load a group of routes.
For example:
admin/
├── admin.routes.ts
├── dashboard.ts
├── users.ts
└── reports.ts
Main routes:
export const routes: Routes = [
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.routes')
.then(m => m.ADMIN_ROUTES)
}
];
admin/admin.routes.ts:
import { Routes } from '@angular/router';
export const ADMIN_ROUTES: Routes = [
{
path: 'dashboard',
loadComponent: () =>
import('./dashboard')
.then(m => m.Dashboard)
},
{
path: 'users',
loadComponent: () =>
import('./users')
.then(m => m.Users)
}
];
Now the entire Admin route configuration is loaded only when the user enters:
/admin/...
6. Before Standalone Angular
Traditionally, Angular applications commonly lazy-loaded NgModules.
For example:
{
path: 'products',
loadChildren: () =>
import('./products/products.module')
.then(m => m.ProductsModule)
}
The structure might have been:
products/
├── products.module.ts
├── products-routing.module.ts
├── products.component.ts
└── products.component.html
The lazy-loading unit was typically the feature module.
7. Modern Standalone Angular
Standalone Angular does not require an NgModule just to lazy-load a feature.
You can lazy-load a component directly:
{
path: 'products',
loadComponent: () =>
import('./products/products')
.then(m => m.Products)
}
Or lazy-load a route collection:
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.routes')
.then(m => m.ADMIN_ROUTES)
}
So the evolution is roughly:
Traditional Angular
Route
↓
loadChildren()
↓
Feature NgModule
↓
Component
Modern standalone Angular:
Route
↓
loadComponent()
↓
Standalone Component
or:
Route
↓
loadChildren()
↓
Routes
↓
Standalone Components
8. Why is Lazy Loading Important?
Consider a large application:
Home 300 KB
Products 500 KB
Orders 400 KB
Admin 600 KB
Reports 500 KB
Without code splitting/lazy loading, much more code may be needed during initial startup.
Conceptually:
Initial Download
↓
Home
Products
Orders
Admin
Reports
With lazy loading:
Initial Download
↓
Core/Home
/products
↓
Products chunk
/admin
↓
Admin chunk
The exact bundle sizes and splitting depend on the build, but the key idea is that code for lazy routes can be deferred until needed.
9. Advantages
Lazy loading can provide:
- Smaller initial bundle
- Faster initial startup
- Less JavaScript to initially download, parse, and execute
- Better scalability for large applications
- Logical separation of application features
- Users don't immediately download code for features they never visit
It is especially useful for areas such as:
Admin
Reports
Settings
Orders
Analytics
Management screens
10. Key Points
| Concept | Meaning |
|---|---|
| Lazy Loading | Load code only when needed |
| Eager Loading | Code is part of the eagerly loaded dependency graph |
loadComponent() |
Lazy-load a standalone component |
loadChildren() |
Lazy-load child routes/feature route configuration |
import() |
Dynamic import enabling code splitting |
| Main benefit | Reduce initial JavaScript workload |
| Traditional Angular | Commonly lazy-loaded feature NgModules |
| Modern Angular | Can lazy-load standalone components and route collections |
A useful interview definition is:
Lazy loading in Angular is a technique that loads feature code only when it is required, typically when the user navigates to a route. It reduces the initial bundle size and can improve application startup performance.
11. Interview Questions and Answers
1. What is lazy loading in Angular?
Lazy loading means loading a feature or component only when it is required, instead of including all feature code in the initial application load.
2. Why do we use lazy loading?
Primarily to reduce the application's initial JavaScript workload and improve startup performance, especially in large applications.
3. How do you lazy-load a standalone component?
Using loadComponent():
{
path: 'products',
loadComponent: () =>
import('./products/products')
.then(m => m.Products)
}
4. What is loadChildren()?
loadChildren() lazy-loads a set of child routes or, in older Angular architectures, a feature NgModule.
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.routes')
.then(m => m.ADMIN_ROUTES)
}
5. What is the difference between loadComponent() and loadChildren()?
loadComponent()
↓
Single standalone component
loadChildren()
↓
Collection of routes / feature area
6. What is the difference between eager loading and lazy loading?
Eager loading makes feature code reachable from the initial application dependency graph.
Lazy loading splits feature code so it can be fetched later when the route is accessed.
7. How was lazy loading implemented before standalone Angular?
It was commonly implemented by lazy-loading an NgModule:
loadChildren: () =>
import('./products/products.module')
.then(m => m.ProductsModule)
8. Does lazy loading mean the page is loaded from ASP.NET Core Web API?
No.
These are separate concepts:
Lazy Loading
↓
Loads Angular JavaScript/code
HttpClient
↓
Loads data from ASP.NET Core Web API
For example:
User opens /products
↓
Angular lazy-loads Products component
↓
Products component starts
↓
HttpClient
↓
ASP.NET Core Web API
↓
SQL Server
↓
Product data returned
This distinction is particularly important in an Angular + ASP.NET Core Web API architecture.