search
Angular star Featured

Fix: Lazy loading module not working in Angular

Learn how to fix lazy loading module issues in Angular applications. This comprehensive guide covers routing, configuration, and best practices for lazy loading.

person By Gautam Sharma
calendar_today January 2, 2026
schedule 12 min read
Angular Lazy Loading Routing Module Performance Frontend Development

The ‘Lazy loading module not working in Angular’ is a common routing and performance optimization issue that occurs when Angular modules fail to load on-demand. This problem typically manifests when navigating to routes that should trigger lazy loading, but instead result in errors, blank pages, or modules loading immediately instead of on-demand.

This comprehensive guide explains what causes this issue, why it happens, and provides multiple solutions to fix it in your Angular projects with clean code examples and directory structure.


What is the Lazy Loading Module Issue?

The “Lazy loading module not working” issue occurs when:

  • Lazy-loaded modules fail to load when navigating to their routes
  • Modules load immediately instead of on-demand
  • Navigation to lazy-loaded routes results in errors
  • Bundle splitting doesn’t occur as expected
  • Preloading strategies don’t work properly

Common Error Messages:

  • Cannot match any routes. URL Segment: 'path'
  • Module not found: Error: Can't resolve './path/to/module'
  • Unexpected value 'undefined' imported by the module
  • Error: StaticInjectorError[RouterModule]
  • Lazy-loaded modules are not being split in the build

Understanding the Problem

Angular’s lazy loading feature allows modules to be loaded on-demand when their routes are accessed, improving initial application load time. The issue typically occurs due to:

  • Incorrect route configuration
  • Missing module exports
  • Incorrect import syntax
  • Build configuration issues
  • Module structure problems

Typical Angular Project Structure:

my-angular-app/
├── package.json
├── angular.json
├── src/
│   ├── app/
│   │   ├── app.component.ts
│   │   ├── app.component.html
│   │   ├── app.module.ts
│   │   ├── app-routing.module.ts
│   │   ├── shared/
│   │   │   └── shared.module.ts
│   │   └── features/
│   │       ├── feature-one/
│   │       │   ├── feature-one.module.ts
│   │       │   ├── feature-one.component.ts
│   │       │   └── feature-one-routing.module.ts
│   │       └── feature-two/
│   │           ├── feature-two.module.ts
│   │           ├── feature-two.component.ts
│   │           └── feature-two-routing.module.ts
│   └── index.html
└── node_modules/

Solution 1: Correct Route Configuration

The most common cause is incorrect route configuration for lazy loading.

❌ Incorrect Route Configuration:

// src/app/app-routing.module.ts - ❌ Wrong lazy loading syntax
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { FeatureOneModule } from './features/feature-one/feature-one.module';

const routes: Routes = [
  {
    path: 'feature-one',
    // ❌ Importing module directly instead of using loadChildren
    component: FeatureOneModule // ❌ Wrong approach
  }
];

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

✅ Correct Route Configuration:

app-routing.module.ts:

// src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: 'feature-one',
    // ✅ Correct lazy loading syntax
    loadChildren: () => import('./features/feature-one/feature-one.module').then(m => m.FeatureOneModule)
  },
  {
    path: 'feature-two',
    // ✅ Another lazy-loaded module
    loadChildren: () => import('./features/feature-two/feature-two.module').then(m => m.FeatureTwoModule)
  },
  {
    path: '',
    redirectTo: '/feature-one',
    pathMatch: 'full'
  }
];

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

Solution 2: Proper Module Structure

Ensure your lazy-loaded modules have the correct structure and exports.

❌ Incorrect Module Structure:

// src/app/features/feature-one/feature-one.module.ts - ❌ Missing exports
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FeatureOneComponent } from './feature-one.component';

@NgModule({
  declarations: [
    FeatureOneComponent
  ],
  imports: [
    CommonModule
    // ❌ Missing routing module
  ]
  // ❌ Missing exports
})
export class FeatureOneModule { }

✅ Correct Module Structure:

feature-one.module.ts:

// src/app/features/feature-one/feature-one.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FeatureOneRoutingModule } from './feature-one-routing.module';
import { FeatureOneComponent } from './feature-one.component';

@NgModule({
  declarations: [
    FeatureOneComponent
  ],
  imports: [
    CommonModule,
    FeatureOneRoutingModule // ✅ Import routing module
  ],
  exports: [
    FeatureOneComponent
  ]
})
export class FeatureOneModule { }

feature-one-routing.module.ts:

// src/app/features/feature-one/feature-one-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { FeatureOneComponent } from './feature-one.component';

const routes: Routes = [
  {
    path: '',
    component: FeatureOneComponent
  }
];

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

Solution 3: Fix Import/Export Issues

Ensure proper module imports and exports for lazy loading.

❌ Missing Module Exports:

// ❌ Module doesn't export what's needed
@NgModule({
  declarations: [FeatureComponent],
  imports: [CommonModule, FeatureRoutingModule]
  // ❌ Missing exports
})
export class FeatureModule { }

✅ Proper Exports:

// ✅ Export components that might be used elsewhere
@NgModule({
  declarations: [FeatureComponent],
  imports: [CommonModule, FeatureRoutingModule],
  exports: [FeatureComponent] // ✅ Export if needed by other modules
})
export class FeatureModule { }

Solution 4: Handle Shared Dependencies

Ensure shared modules and services are properly handled in lazy-loaded modules.

shared.module.ts:

// src/app/shared/shared.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

@NgModule({
  declarations: [],
  imports: [CommonModule],
  exports: []
})
export class SharedModule { }

feature-one.module.ts:

// src/app/features/feature-one/feature-one.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '../../shared/shared.module'; // ✅ Import shared module if needed
import { FeatureOneRoutingModule } from './feature-one-routing.module';
import { FeatureOneComponent } from './feature-one.component';

@NgModule({
  declarations: [
    FeatureOneComponent
  ],
  imports: [
    CommonModule,
    SharedModule, // ✅ Import shared functionality
    FeatureOneRoutingModule
  ]
})
export class FeatureOneModule { }

Solution 5: Configure Preloading Strategy

Set up proper preloading strategies for better user experience.

app-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes, PreloadAllModules } from '@angular/router';

const routes: Routes = [
  {
    path: 'feature-one',
    loadChildren: () => import('./features/feature-one/feature-one.module').then(m => m.FeatureOneModule)
  },
  {
    path: 'feature-two',
    loadChildren: () => import('./features/feature-two/feature-two.module').then(m => m.FeatureTwoModule)
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, {
    preloadingStrategy: PreloadAllModules // ✅ Preload all modules (optional)
  })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Solution 6: Custom Preloading Strategy

Implement custom preloading strategies for specific use cases.

custom-preloading.service.ts:

import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class CustomPreloadingService implements PreloadingStrategy {
  preload(route: Route, load: () => Observable<any>): Observable<any> {
    // ✅ Preload only routes with data.preload = true
    if (route.data && route.data['preload']) {
      return load();
    }
    return of(null);
  }
}

app-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomPreloadingService } from './services/custom-preloading.service';

const routes: Routes = [
  {
    path: 'feature-one',
    loadChildren: () => import('./features/feature-one/feature-one.module').then(m => m.FeatureOneModule),
    data: { preload: true } // ✅ Preload this module
  },
  {
    path: 'feature-two',
    loadChildren: () => import('./features/feature-two/feature-two.module').then(m => m.FeatureTwoModule)
    // ✅ Don't preload this module
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, {
    preloadingStrategy: CustomPreloadingService // ✅ Use custom preloading
  })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Solution 7: Handle Service Dependencies

Ensure services are provided correctly in lazy-loaded modules.

feature.service.ts:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root' // ✅ Provided in root for global access
})
export class FeatureService {
  getData() {
    return 'Feature data';
  }
}

feature-one.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FeatureOneRoutingModule } from './feature-one-routing.module';
import { FeatureOneComponent } from './feature-one.component';
import { FeatureService } from './feature.service';

@NgModule({
  declarations: [
    FeatureOneComponent
  ],
  imports: [
    CommonModule,
    FeatureOneRoutingModule
  ],
  providers: [
    // ✅ Only provide services specific to this module
    // FeatureService is provided in root, so no need to provide here
  ]
})
export class FeatureOneModule { }

Working Code Examples

Complete Lazy-Loaded Module Example:

// src/app/features/dashboard/dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { FeatureService } from './feature.service';

@Component({
  selector: 'app-dashboard',
  template: `
    <div class="dashboard">
      <h2>Dashboard</h2>
      <p>{{ data }}</p>
      <button (click)="loadData()">Load Data</button>
    </div>
  `,
  styles: [`
    .dashboard { padding: 20px; }
  `]
})
export class DashboardComponent implements OnInit {
  data = '';

  constructor(private featureService: FeatureService) {}

  ngOnInit() {
    this.data = this.featureService.getData();
  }

  loadData() {
    this.data = this.featureService.getData();
  }
}

dashboard.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DashboardRoutingModule } from './dashboard-routing.module';
import { DashboardComponent } from './dashboard.component';
import { FeatureService } from './feature.service';

@NgModule({
  declarations: [
    DashboardComponent
  ],
  imports: [
    CommonModule,
    DashboardRoutingModule
  ],
  providers: [
    FeatureService // ✅ Service specific to this module
  ]
})
export class DashboardModule { }

dashboard-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard.component';

const routes: Routes = [
  {
    path: '',
    component: DashboardComponent
  }
];

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

Main App Module:

// src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule // ✅ Contains lazy-loaded routes
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Best Practices for Lazy Loading

1. Use Proper Import Syntax

// ✅ Always use dynamic imports for lazy loading
loadChildren: () => import('./path/to/module').then(m => m.ModuleName)

2. Organize Features by Domain

// ✅ Group related components in feature modules
// features/user-management/
// features/products/
// features/orders/

3. Implement Proper Error Handling

// ✅ Handle lazy loading errors
loadChildren: () => import('./feature.module').then(m => m.FeatureModule)
  .catch(error => {
    console.error('Failed to load feature module:', error);
    // Redirect to error page or show error message
  })

4. Monitor Bundle Size

# ✅ Use Angular CLI to analyze bundle size
ng build --stats-json
npx webpack-bundle-analyzer dist/my-app/stats.json

Debugging Steps

Step 1: Check Route Configuration

# Verify route configuration syntax
grep -r "loadChildren" src/app/

Step 2: Test Lazy Loading

# Build with verbose output to see lazy loading
ng build --verbose

Step 3: Check Network Tab

# In browser dev tools, check network tab
# Lazy-loaded modules should load on demand

Step 4: Verify Module Structure

# Check if modules have proper routing and exports
ls -la src/app/features/*/feature-*-routing.module.ts

Common Mistakes to Avoid

1. Incorrect Import Syntax

// ❌ Wrong syntax
loadChildren: './path/to/module#Module'

// ✅ Correct syntax
loadChildren: () => import('./path/to/module').then(m => m.Module)

2. Missing Routing Module

// ❌ Feature module without routing module
@NgModule({
  declarations: [Component],
  imports: [CommonModule] // ❌ Missing routing
})
export class FeatureModule { }

3. Circular Dependencies

// ❌ Avoid circular imports between modules
// Module A imports Module B, Module B imports Module A

4. Providing Services in Multiple Places

// ❌ Don't provide the same service in multiple modules
// unless you want different instances

Performance Considerations

1. Optimize Bundle Splitting

# ✅ Verify bundle splitting works
ng build --configuration=production
# Check that separate chunks are created for lazy-loaded modules

2. Implement Preloading Strategically

// ✅ Use preloading for critical modules
// Don't preload all modules if it affects initial load time

3. Lazy Load Heavy Components

// ✅ Lazy load components with heavy dependencies
// Charts, editors, complex forms, etc.

Security Considerations

1. Validate Dynamic Imports

// ✅ Ensure dynamic imports come from trusted sources
// Don't allow user input to determine module paths

2. Sanitize Route Parameters

// ✅ Always validate route parameters
// before using them in dynamic imports

Testing Lazy Loading

1. Unit Test Route Configuration

import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { Router } from '@angular/router';

describe('Lazy Loading', () => {
  let router: Router;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule.withRoutes([
        {
          path: 'feature',
          loadChildren: () => import('./features/feature.module').then(m => m.FeatureModule)
        }
      ])]
    });

    router = TestBed.inject(Router);
  });

  it('should navigate to lazy-loaded route', async () => {
    const navigateResult = await router.navigateByUrl('/feature');
    expect(navigateResult).toBe(true);
  });
});

2. E2E Test Lazy Loading

// Using Protractor or Cypress
// Verify that lazy-loaded modules load when navigating to their routes

Alternative Solutions

1. Component-Level Lazy Loading

// For simple components, use dynamic component loading
import { ComponentFactoryResolver, ViewContainerRef } from '@angular/core';

export class MyComponent {
  constructor(
    private resolver: ComponentFactoryResolver,
    private container: ViewContainerRef
  ) {}

  loadComponent() {
    import('./dynamic-component').then(module => {
      const factory = this.resolver.resolveComponentFactory(module.DynamicComponent);
      this.container.createComponent(factory);
    });
  }
}

2. Preload Specific Modules

// Use route data to preload specific modules
{
  path: 'important-feature',
  loadChildren: () => import('./feature.module').then(m => m.FeatureModule),
  data: { preload: true }
}

Migration Checklist

  • Verify all lazy-loaded routes use correct import syntax
  • Check that feature modules have proper routing modules
  • Ensure modules export necessary components
  • Test navigation to lazy-loaded routes
  • Verify bundle splitting in production build
  • Check preloading strategies work as expected
  • Update documentation for team members

Conclusion

The ‘Lazy loading module not working in Angular’ issue is typically caused by incorrect route configuration, missing module exports, or improper import syntax. By following the solutions provided in this guide—whether through proper route configuration, correct module structure, or strategic preloading—you can ensure your Angular applications effectively implement lazy loading for improved performance.

The key is to understand Angular’s lazy loading mechanism, use the correct dynamic import syntax, and ensure proper module structure with routing modules. With proper lazy loading implementation, your Angular applications will have faster initial load times, better performance, and improved user experience.

Remember to test lazy loading thoroughly, monitor bundle sizes, and follow Angular’s best practices for module organization to maintain optimal performance throughout your application lifecycle.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

Angular

Fix: Angular ExpressionChangedAfterItHasBeenCheckedError Error

Learn how to fix the 'ExpressionChangedAfterItHasBeenCheckedError' in Angular. This comprehensive guide covers change detection, lifecycle hooks, and best practices.

January 2, 2026
Angular

Fix: Angular app not working after build (production issue)

Learn how to fix Angular applications that don't work after production build. This comprehensive guide covers common production issues, optimization, and best practices.

January 2, 2026
Angular

How to Fix Cannot find module '@angular/compiler-cli Error in Angular'

Learn how to fix the 'Cannot find module @angular/compiler-cli' error in Angular projects. This comprehensive guide covers installation, dependencies, and best practices.

January 2, 2026