Angular Lazy Loading: Load Routes and Components on Demand

Angular Tutorial: Beginner to Advanced · 9. Routing and navigation · 3 min read · Updated

By default the browser downloads the whole app before the first page appears. Lazy loading splits the app into pieces and downloads a page only when someone visits it. Smaller first downloads mean faster pages.

What you will learn

  • How to lazy load a route with loadComponent
  • How to lazy load a group of routes with loadChildren
  • How to read the build output and how @defer works

Lazy load a single page

Change the routes so heavy pages are imported when needed. Notice that the page imports are removed from the top of the file.

// src/app/app.routes.ts
import { Routes } from '@angular/router';
import { Home } from './pages/home';
import { NotFound } from './pages/not-found';
import { authGuard } from './auth-guard';

export const routes: Routes = [
  { path: '', component: Home, title: 'Home' },
  {
    path: 'about',
    loadComponent: () => import('./pages/about').then((m) => m.About),
    title: 'About',
  },
  {
    path: 'products',
    loadChildren: () => import('./products/product.routes').then((m) => m.PRODUCT_ROUTES),
  },
  {
    path: 'login',
    loadComponent: () => import('./auth/login').then((m) => m.Login),
    title: 'Login',
  },
  {
    path: 'dashboard',
    loadComponent: () => import('./auth/dashboard').then((m) => m.Dashboard),
    canActivate: [authGuard],
    title: 'Dashboard',
  },
  { path: '**', component: NotFound, title: 'Not found' },
];

Lazy load a group of routes

// src/app/products/product.routes.ts
import { Routes } from '@angular/router';
import { ProductList } from './product-list';
import { ProductDetail } from './product-detail';

export const PRODUCT_ROUTES: Routes = [
  { path: '', component: ProductList, title: 'Products' },
  { path: ':id', component: ProductDetail, title: 'Product details' },
];

The products path is now a prefix. /products matches the empty child path, and /products/3 matches :id. The product pages are downloaded only when someone opens /products.

See it in the build

Run the production build:

ng build

The output now lists several lazy chunk files next to the initial bundle, with names based on the pages, such as chunk-XXXX.js. The initial total is smaller than before because the lazy pages are not included.

Defer parts of a page

Inside a template, @defer loads a section later, for example when it scrolls into view:

@defer (on viewport) {
  <app-reviews />
} @placeholder {
  <p>Reviews will load when you scroll here.</p>
} @loading {
  <p>Loading reviews...</p>
}

The components used inside @defer are moved to their own chunk. Use it for heavy parts below the fold, not for content that matters for search or the first view.

The key parts

  • loadComponent and loadChildren use the dynamic import() of JavaScript, which the build tool turns into a separate file.
  • Keep the first page (Home) eager. A lazy first page just adds a delay.
  • Do not import a lazy component in another file's imports or route, or it goes back into the main bundle.
  • @defer triggers include on viewport, on idle, on interaction and on timer(...).

Try it yourself

  1. Run ng build before and after this lesson and compare the initial total size.
  2. Open the browser DevTools Network tab and watch a chunk download when you click About.
  3. Lazy load the Contact page you created earlier.

Quick check

  1. What is the difference between loadComponent and loadChildren?
  2. Why should the home page usually not be lazy loaded?
  3. What does @defer (on viewport) do?

You can now move between pages. Next, get data from a server with HttpClient. Read more in the lazy loading guide.

Frequently asked questions

Does lazy loading hurt SEO?

Not by itself. Search engines run JavaScript, but for public content pages, consider server-side rendering so the content is in the first HTML.

How do I preload lazy routes?

Add withPreloadingStrategy(PreloadAllModules) to provideRouter to download them in the background after the first load.