Skip to content
SunnyWriteUps
Go back

How would you architect a large Angular app for dynamic module loading, lazy loading, and role-based access?

Edit page

High-Level Architecture

App

├── Core Module
│   ├── Authentication
│   ├── Authorization
│   ├── HTTP Interceptors
│   ├── Global Services
│   └── Route Guards

├── Shared Module
│   ├── Reusable Components
│   ├── Pipes
│   ├── Directives
│   └── Utility Services

├── Feature Modules
│   ├── Dashboard
│   ├── Orders
│   ├── Users
│   ├── Reports
│   └── Admin

└── Shell
    ├── Layout
    ├── Navigation
    └── Dynamic Menu

1. Lazy Loading Feature Modules

Load feature modules only when users navigate to them.

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

Benefits


2. Dynamic Module Loading

If modules depend on feature flags, plugins, or tenant configurations:

const moduleMap = {
  reports: () =>
    import('./features/reports/reports.module'),
  analytics: () =>
    import('./features/analytics/analytics.module')
};

Configuration:

{
  "enabledModules": [
    "reports",
    "analytics"
  ]
}

The application loads only enabled modules at runtime.

This approach works well for:


3. Role-Based Access Control (RBAC)

Example roles:

Admin
Manager
Employee
Guest

Authentication returns:

{
  "user": "John",
  "roles": [
    "Admin",
    "Manager"
  ]
}

Route configuration:

{
  path: 'admin',
  canActivate: [AuthGuard, RoleGuard],
  data: {
    roles: ['Admin']
  },
  loadChildren: () =>
    import('./admin/admin.module')
      .then(m => m.AdminModule)
}

Guard:

canActivate(route: ActivatedRouteSnapshot) {
    const roles = route.data['roles'];
    return this.authService.hasRole(roles);
}

For even better performance, use canMatch to prevent unauthorized lazy-loaded modules from being matched in the first place.


4. Dynamic Navigation

Generate menus based on permissions.

[
  {
    title: 'Dashboard',
    roles: ['Admin','Manager','Employee']
  },
  {
    title: 'Admin',
    roles: ['Admin']
  }
]

The UI displays only the pages the user can access.


5. Preloading Strategy

Preload modules after the app becomes idle.

RouterModule.forRoot(routes, {
    preloadingStrategy: PreloadAllModules
});

Or create a custom preloading strategy:

Load immediately

User becomes idle

Preload Reports

Preload Settings

Cache modules

This reduces wait times during navigation.


6. Feature-Based State Management

Keep state isolated within feature modules.

Orders Module
    └── Orders Store

Reports Module
    └── Reports Store

Admin Module
    └── Admin Store

This avoids a single, oversized global store and improves maintainability.


7. Security

UI checks alone are not sufficient.

Always:


8. Performance Optimizations


Example Flow

User Login


Authenticate User


Receive Roles + Permissions


Build Dynamic Navigation


User Clicks "Reports"


Role Guard / canMatch Checks Access


Lazy Load Reports Module


Initialize Feature State


Render Reports

For a modern enterprise Angular application, I would use:

This architecture keeps the application modular, secure, and performant as it grows to dozens of features and millions of users.


Edit page
Share this post on:

Previous Post
MongoDB from Development to Production A Complete Guide with Best Practices
Next Post
Enterprise-Grade AI Building the Agentverse with RAG, Knowledge Engines & Secure Scalable Inference