> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/angular/angular/llms.txt
> Use this file to discover all available pages before exploring further.

# Lazy Loading

> Implement lazy loading to optimize bundle size and improve application performance

Lazy loading allows you to load Angular modules or components on-demand rather than at application startup. This reduces the initial bundle size and improves load times, especially for large applications.

## Why Lazy Loading?

Benefits of lazy loading:

* **Smaller Initial Bundle**: Load only what's needed for the initial view
* **Faster Startup**: Reduce application bootstrap time
* **Better Performance**: Load features only when users need them
* **Efficient Resources**: Minimize memory usage by loading code on-demand

<Info>
  Lazy loading is implemented using dynamic imports (`import()`) and the `loadChildren` or `loadComponent` properties in route configurations. The implementation can be found in `packages/router/src/router_config_loader.ts`.
</Info>

## Lazy Loading Routes

### Using loadChildren (Recommended)

The modern approach uses `loadChildren` with dynamic imports:

```typescript app.routes.ts theme={null}
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'home',
    component: HomeComponent
  },
  {
    path: 'products',
    loadChildren: () => import('./products/products.routes')
      .then(m => m.PRODUCTS_ROUTES)
  },
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes')
      .then(m => m.ADMIN_ROUTES)
  }
];
```

```typescript products/products.routes.ts theme={null}
import { Routes } from '@angular/router';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductDetailComponent } from './product-detail/product-detail.component';

export const PRODUCTS_ROUTES: Routes = [
  {
    path: '',
    component: ProductListComponent
  },
  {
    path: ':id',
    component: ProductDetailComponent
  }
];
```

### Default Exports

You can also use default exports:

```typescript products/products.routes.ts theme={null}
import { Routes } from '@angular/router';

const routes: Routes = [
  // ... route definitions
];

export default routes; // Default export
```

```typescript app.routes.ts theme={null}
export const routes: Routes = [
  {
    path: 'products',
    // .then() is optional with default exports
    loadChildren: () => import('./products/products.routes')
  }
];
```

## Lazy Loading Components

### Standalone Components

Lazy load individual components with `loadComponent`:

```typescript app.routes.ts theme={null}
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'about',
    loadComponent: () => import('./about/about.component')
      .then(m => m.AboutComponent)
  },
  {
    path: 'contact',
    loadComponent: () => import('./contact/contact.component')
      .then(m => m.ContactComponent)
  }
];
```

```typescript about/about.component.ts theme={null}
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-about',
  standalone: true,
  imports: [CommonModule],
  template: `
    <h1>About Us</h1>
    <p>This component is lazy loaded!</p>
  `
})
export class AboutComponent {}
```

<Info>
  The `loadComponent` property is defined in `packages/router/src/models.ts:626` and supports lazy loading standalone components.
</Info>

## Lazy Loading NgModules (Legacy)

For applications still using NgModules:

```typescript app-routing.module.ts theme={null}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

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

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}
```

```typescript products/products.module.ts theme={null}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductDetailComponent } from './product-detail/product-detail.component';

const routes: Routes = [
  { path: '', component: ProductListComponent },
  { path: ':id', component: ProductDetailComponent }
];

@NgModule({
  declarations: [ProductListComponent, ProductDetailComponent],
  imports: [RouterModule.forChild(routes)]
})
export class ProductsModule {}
```

<Warning>
  NgModule lazy loading is legacy. For new projects, use standalone components with `loadComponent` or route arrays with `loadChildren`.
</Warning>

## Guards with Lazy Loading

### Using canMatch for Lazy Routes

`canMatch` guards prevent lazy-loaded modules from loading:

```typescript feature-flag.guard.ts theme={null}
import { inject } from '@angular/core';
import { CanMatchFn } from '@angular/router';
import { FeatureFlagService } from './feature-flag.service';

export const featureFlagGuard: CanMatchFn = (route, segments) => {
  const featureFlags = inject(FeatureFlagService);
  const featureName = route.data?.['feature'];
  
  // Prevent module from loading if feature is disabled
  return featureFlags.isEnabled(featureName);
};
```

```typescript routes.ts theme={null}
export const routes: Routes = [
  {
    path: 'premium',
    loadChildren: () => import('./premium/premium.routes')
      .then(m => m.PREMIUM_ROUTES),
    canMatch: [featureFlagGuard],
    data: { feature: 'premium-features' }
  }
];
```

### Using canActivate

`canActivate` guards run after the module loads:

```typescript auth.guard.ts theme={null}
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';

export const authGuard: CanActivateFn = (route, state) => {
  const authService = inject(AuthService);
  const router = inject(Router);
  
  if (authService.isLoggedIn()) {
    return true;
  }
  
  return router.createUrlTree(['/login']);
};
```

```typescript routes.ts theme={null}
export const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.routes')
      .then(m => m.DASHBOARD_ROUTES),
    canActivate: [authGuard] // Module loads, then guard runs
  }
];
```

<Note>
  Use `canMatch` when you want to prevent loading. Use `canActivate` when the module should load but activation depends on a condition.
</Note>

## Preloading Strategies

Preloading loads lazy routes in the background after initial load:

### PreloadAllModules

Preload all lazy routes automatically:

```typescript main.ts theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { 
  provideRouter, 
  withPreloading, 
  PreloadAllModules 
} from '@angular/router';
import { routes } from './app/app.routes';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(
      routes,
      withPreloading(PreloadAllModules) // Preload all lazy routes
    )
  ]
});
```

### NoPreloading (Default)

Disable preloading (load only on-demand):

```typescript main.ts theme={null}
import { provideRouter, NoPreloading, withPreloading } from '@angular/router';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(
      routes,
      withPreloading(NoPreloading) // Explicit no preloading
    )
  ]
});
```

### Custom Preloading Strategy

Create a custom strategy for selective preloading:

```typescript custom-preload.strategy.ts theme={null}
import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of, timer } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class CustomPreloadStrategy implements PreloadingStrategy {
  preload(route: Route, load: () => Observable<any>): Observable<any> {
    // Preload if route has 'preload' data property
    if (route.data?.['preload']) {
      // Optional: delay preloading
      const delay = route.data?.['preloadDelay'] || 0;
      return timer(delay).pipe(
        mergeMap(() => {
          console.log('Preloading:', route.path);
          return load();
        })
      );
    }
    
    return of(null); // Don't preload
  }
}
```

```typescript routes.ts theme={null}
export const routes: Routes = [
  {
    path: 'products',
    loadChildren: () => import('./products/products.routes')
      .then(m => m.PRODUCTS_ROUTES),
    data: { preload: true } // Will be preloaded
  },
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes')
      .then(m => m.ADMIN_ROUTES),
    data: { 
      preload: true, 
      preloadDelay: 5000 // Preload after 5 seconds
    }
  },
  {
    path: 'reports',
    loadChildren: () => import('./reports/reports.routes')
      .then(m => m.REPORTS_ROUTES)
    // No preload data - won't be preloaded
  }
];
```

```typescript main.ts theme={null}
import { CustomPreloadStrategy } from './custom-preload.strategy';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(
      routes,
      withPreloading(CustomPreloadStrategy)
    )
  ]
});
```

## Network-Aware Preloading

Preload based on network conditions:

```typescript network-aware-preload.strategy.ts theme={null}
import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class NetworkAwarePreloadStrategy implements PreloadingStrategy {
  preload(route: Route, load: () => Observable<any>): Observable<any> {
    const shouldPreload = route.data?.['preload'];
    
    if (!shouldPreload) {
      return of(null);
    }
    
    // Check network connection
    const connection = (navigator as any).connection;
    
    if (connection) {
      // Don't preload on slow connections
      if (connection.effectiveType === 'slow-2g' || 
          connection.effectiveType === '2g') {
        console.log('Skipping preload on slow connection');
        return of(null);
      }
      
      // Don't preload if data saver is on
      if (connection.saveData) {
        console.log('Skipping preload with data saver enabled');
        return of(null);
      }
    }
    
    console.log('Preloading:', route.path);
    return load();
  }
}
```

## Lazy Loading with Providers

Provide services scoped to lazy-loaded routes:

```typescript products/products.routes.ts theme={null}
import { Routes } from '@angular/router';
import { ProductService } from './product.service';
import { ProductListComponent } from './product-list.component';
import { ProductDetailComponent } from './product-detail.component';

export const PRODUCTS_ROUTES: Routes = [
  {
    path: '',
    providers: [
      ProductService // Scoped to this route and children
    ],
    children: [
      {
        path: '',
        component: ProductListComponent
      },
      {
        path: ':id',
        component: ProductDetailComponent
      }
    ]
  }
];
```

## Performance Monitoring

Monitor lazy loading performance:

```typescript app.component.ts theme={null}
import { Component, inject } from '@angular/core';
import { Router, RouteConfigLoadStart, RouteConfigLoadEnd } from '@angular/router';

@Component({
  selector: 'app-root',
  template: `
    <div *ngIf="loading" class="loading-indicator">
      Loading module...
    </div>
    <router-outlet></router-outlet>
  `
})
export class AppComponent {
  private router = inject(Router);
  loading = false;

  ngOnInit() {
    this.router.events.subscribe(event => {
      if (event instanceof RouteConfigLoadStart) {
        this.loading = true;
        console.log('Loading module:', event.route.path);
      } else if (event instanceof RouteConfigLoadEnd) {
        this.loading = false;
        console.log('Module loaded:', event.route.path);
      }
    });
  }
}
```

## Real-World Example

Comprehensive lazy loading setup:

```typescript app.routes.ts theme={null}
import { Routes } from '@angular/router';
import { authGuard } from './guards/auth.guard';
import { adminGuard } from './guards/admin.guard';

export const routes: Routes = [
  // Eager loaded routes
  {
    path: '',
    loadComponent: () => import('./home/home.component')
      .then(m => m.HomeComponent)
  },
  {
    path: 'login',
    loadComponent: () => import('./auth/login.component')
      .then(m => m.LoginComponent)
  },
  
  // Lazy loaded with preloading
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.routes')
      .then(m => m.DASHBOARD_ROUTES),
    canActivate: [authGuard],
    data: { preload: true }
  },
  
  // Lazy loaded without preloading
  {
    path: 'reports',
    loadChildren: () => import('./reports/reports.routes')
      .then(m => m.REPORTS_ROUTES),
    canActivate: [authGuard],
    data: { preload: false }
  },
  
  // Admin section - delayed preload
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes')
      .then(m => m.ADMIN_ROUTES),
    canActivate: [authGuard, adminGuard],
    data: { 
      preload: true,
      preloadDelay: 3000
    }
  },
  
  // Settings - lazy component
  {
    path: 'settings',
    loadComponent: () => import('./settings/settings.component')
      .then(m => m.SettingsComponent),
    canActivate: [authGuard]
  }
];
```

```typescript main.ts theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withPreloading } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
import { CustomPreloadStrategy } from './app/custom-preload.strategy';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(
      routes,
      withPreloading(CustomPreloadStrategy)
    )
  ]
});
```

## Bundle Analysis

Analyze your lazy-loaded bundles:

```bash theme={null}
# Generate stats file
ng build --stats-json

# Analyze with webpack-bundle-analyzer
npx webpack-bundle-analyzer dist/your-app/stats.json
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Group by Feature" icon="folder-tree">
    Organize lazy-loaded modules by feature or functionality for better maintainability.
  </Card>

  <Card title="Use Smart Preloading" icon="brain">
    Implement custom preloading strategies based on user behavior and network conditions.
  </Card>

  <Card title="Monitor Bundle Sizes" icon="chart-simple">
    Regularly analyze bundle sizes to identify optimization opportunities.
  </Card>

  <Card title="Prefer canMatch for Lazy Routes" icon="filter">
    Use `canMatch` guards to prevent unnecessary module downloads.
  </Card>
</CardGroup>

## Common Patterns

### Feature Shell Pattern

Create a shell component for lazy-loaded features:

```typescript products/products.routes.ts theme={null}
import { Routes } from '@angular/router';
import { ProductsShellComponent } from './products-shell.component';

export const PRODUCTS_ROUTES: Routes = [
  {
    path: '',
    component: ProductsShellComponent, // Shell with shared layout
    children: [
      {
        path: '',
        loadComponent: () => import('./product-list/product-list.component')
          .then(m => m.ProductListComponent)
      },
      {
        path: ':id',
        loadComponent: () => import('./product-detail/product-detail.component')
          .then(m => m.ProductDetailComponent)
      }
    ]
  }
];
```

### Conditional Lazy Loading

Load different modules based on conditions:

```typescript routes.ts theme={null}
import { inject } from '@angular/core';
import { Routes } from '@angular/router';
import { UserService } from './user.service';

export const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () => {
      const userService = inject(UserService);
      
      // Load different modules based on user role
      if (userService.isAdmin()) {
        return import('./admin-dashboard/admin-dashboard.routes')
          .then(m => m.ADMIN_DASHBOARD_ROUTES);
      } else {
        return import('./user-dashboard/user-dashboard.routes')
          .then(m => m.USER_DASHBOARD_ROUTES);
      }
    }
  }
];
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Route Guards" icon="lock" href="/routing/route-guards">
    Learn how to protect your lazy-loaded routes with guards
  </Card>

  <Card title="Defining Routes" icon="map" href="/routing/defining-routes">
    Master route configuration and parameters
  </Card>
</CardGroup>
