When building Angular apps with lazy loading, we improve performance by loading feature modules only when needed. But there’s an additional layer of optimization we can apply—preloading certain modules in the background so they’re ready when users navigate to them.
This is where Angular’s preloading strategies come in.
What is Preloading in Angular?
Preloading means loading lazy-loaded modules in the background after the app has initialized. This can reduce wait time when users navigate to a route for the first time.
Angular provides three options:
NoPreloading (default): Modules load only on route activation.
PreloadAllModules: Loads all lazy-loaded modules after app startup.
Custom Preloading Strategy: Loads modules based on your logic.
Why Use Preloading?
Improve perceived performance and navigation speed.
Make use of idle time to load important modules.
Gain control over which modules get preloaded.
Basic Lazy Loading Setup
Let’s first configure some routes with lazy loading:
const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
data: { preload: true }
},
{
path: 'profile',
loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule),
data: { preload: false }
},
];
Using PreloadAllModules
To preload all lazy-loaded modules automatically:
@NgModule({
imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })],
exports: [RouterModule]
})
export class AppRoutingModule {}
This will trigger loading of all lazy-loaded modules after the app has started.
Creating a Custom Preloading Strategy
If you want more fine-grained control, you can create a custom strategy to preload only specific modules.
Step 1: Define the Strategy
// selective-preloading.strategy.ts
@Injectable({ providedIn: 'root' })
export class SelectivePreloadingStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
return route.data?.['preload'] ? load() : of(null);
}
}
Step 2: Register It in the Routing Module
@NgModule({
imports: [RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreloadingStrategy })],
exports: [RouterModule],
providers: [SelectivePreloadingStrategy]
})
export class AppRoutingModule {}
Only routes that have data: { preload: true } will be loaded in the background.
Full Working Example
const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule),
data: { preload: true }
},
{
path: 'settings',
loadChildren: () => import('./settings/settings.module').then(m => m.SettingsModule),
data: { preload: false }
}
];
@Injectable({ providedIn: 'root' })
export class SelectivePreloadingStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
return route.data?.['preload'] ? load() : of(null);
}
}
Summary
Strategy Description
NoPreloading Loads modules only on route activation
PreloadAllModules Loads all lazy modules after app start
Custom Strategy Loads selected modules based on route data
Additional Tips
Combine preloading with route guards to cancel or delay preloading if needed.
Monitor loading behavior using Chrome DevTools (Network tab > JS).
Use preloading selectively to balance performance with user experience.
If you found this helpful and want more frontend architecture tips, patterns, and practical guides, check out my blog:
The Frontend Architect
Top comments (0)