Alula ሐawandoHawandoH→ሐ

Angular router and lazy loading

How to make your Angular apps faster, cleaner, and easier to manage.


Table of Contents

  1. Introduction
  2. Why Routing Matters
  3. Setting Up Angular Routes
  4. What Is Lazy Loading?
  5. How to Implement Lazy Loading in Angular
  6. Creating a Feature Module
  7. Lazy Loading with loadChildren
  8. Shared Module vs Core Module
  9. Route Guards (Bonus)
  10. Best Practices

Introduction

Routers are more than navigations. Especially Angular’s router. It’s how you split your app into manageable chunks, how you optimize performance and how you protect certain parts of your app.

And with lazy loading? You don’t just navigate — you speed up your app. You get performance wins. You scale without chaos.

Let’s see it one by one.


First, Why Routing Matters

In a typical app, never mind a real-world one, you’ll have many pages:

  • Dashboard
  • Login
  • Settings
  • Admin Panel

Without a router, you’d be hardcoding logic and jumping between components manually.

With the router? You map URLs to components. You make things feel like a real app.

// app-routing.module.ts
const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'login', component: LoginComponent }
];

This is basic routing. But what if AdminModule is huge? You don’t want to load it upfront

What Is Lazy Loading?

Lazy loading means: “Don’t load it until you absolutely need it.”

That means, instead of loading everything at the start, Angular loads pieces of your app when you navigate to them.

Why?

  • Faster initial load
  • Better UX
  • You can scale without killing performance

In Angular, lazy loading works at the module level using the loadChildren property.

Setting Up Angular Routes

Let's start with a basic Angular app.

  ng new angular-lazy-demo --routing --style=scss
  cd angular-lazy-demo

You’ll now see an app-routing.module.ts. That’s where your top-level routes go.

How to Implement Lazy Loading in Angular

Let’s say we want to lazy load a DashboardModule.

Step 1: Generate the module

ng generate module features/dashboard --route dashboard --module app.module

The --route flag automatically sets up lazy loading.

// app-routing.module.ts
const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () =>
      import('./features/dashboard/dashboard.module').then(m => m.DashboardModule)
  }
];

That’s it. Lazy loading set up. Just like that!

Creating a Feature Module

Let’s peek inside a feature module like DashboardModule.

// dashboard-routing.module.ts
const routes: Routes = [
  { path: '', component: DashboardHomeComponent },
  { path: 'stats', component: DashboardStatsComponent }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class DashboardRoutingModule {}

Inside dashboard.module.ts, you should import this routing module.

This structure helps you build isolated, lazy-loadable modules.

Lazy Loading with loadChildren

Here’s what’s happening under the hood:

flowchart TD
  A[User visits /dashboard] --> B[Angular Router sees lazy route]
  B --> C[Downloads dashboard.module.js]
  C --> D[Renders DashboardComponent]

Angular waits until the route is activated before downloading the corresponding module.

Shared Module vs Core Module

As you grow, you'll want to reuse components (buttons, cards, pipes).

SharedModule: for reusable UI components

CoreModule: for singleton services (auth, API, guards)

Never lazy load the CoreModule.

Structure your app like:

app/
│
├── core/
│   └── core.module.ts
├── shared/
│   └── shared.module.ts
├── features/
│   ├── dashboard/
│   └── settings/

Route Guards (Bonus)

You can guard lazy-loaded routes too.

{
  path: 'admin',
  loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
  canLoad: [AuthGuard],
  canActivate: [AuthGuard]
}
  • canLoad: prevents the module from even being downloaded
  • canActivate: stops navigation even if module is loaded

Best Practices

✅ Always lazy load feature modules

✅ Use forChild inside feature routing modules

❌ Don’t declare the same component in multiple modules

✅ Keep routes flat (avoid deep nesting unless necessary)

❌ Never lazy load CoreModule