Angular  

Using Micro Frontends for Scalable Web Applications

A Deep-Dive with Angular, Real-World Patterns, and Production Best Practices

Modern web applications have grown in size, complexity, and team distribution. A decade ago, most frontend teams built single applications with a single codebase and a single deployment pipeline. That approach worked when features were limited, team size was small, and business expectations were simpler. But today’s organisations run many parallel product lines, manage several independent release cycles, and expect rapid iteration while keeping user experience consistent. This is where micro frontends have become a major architectural choice.

Micro frontends apply the principles of microservices to the browser. Instead of building one large, monolithic frontend, we split it into smaller, self-contained applications that can be built, deployed, and maintained independently. This architecture promises scalability, faster releases, and better code ownership. However, it also comes with complexity. Implementing micro frontends in a clean, production-safe manner requires careful planning, strong governance, and a mature development culture.

This article is written for senior developers and architects who want a practical and realistic understanding of micro frontends with Angular. It covers conceptual depth, real-world trade-offs, step-by-step implementation details, and proven patterns that work in production-scale systems.

1. Why Micro Frontends?

Micro frontends are not something one implements just because they seem trending. They solve very specific organisational and technical challenges.

When Frontend Monoliths Become a Problem

A monolithic frontend starts becoming hard to manage when:

  1. Teams grow beyond 8–10 developers.
    More people touching the same codebase creates merge conflicts, inconsistent code quality, and slow onboarding.

  2. Features require isolated release cycles.
    One team’s changes often block another team’s deployment.

  3. The build pipeline becomes slower.
    Large builds and test suites increase CI/CD time.

  4. Shared dependencies create version lock-in.
    Upgrading Angular, RxJS, or UI libraries becomes a huge task affecting all teams.

  5. Different parts of the application evolve at different speeds.
    Some modules may require rapid iteration, others remain stable for years.

Micro frontends break this bottleneck by enabling each domain or feature to become an independently maintained slice of the UI.

What Micro Frontends Actually Mean

A micro frontend is not simply:

  • Multiple modules inside one Angular application

  • Lazy-loaded routes

  • A component library

Instead, a micro frontend is a fully independent application that owns:

  • Its own codebase

  • Its own state

  • Its own dependencies

  • Its own build pipeline

  • Its own deployment pipeline

It integrates into a larger shell application at runtime, not compile time.

Business Benefits

The architecture becomes worthwhile when:

  • You have multiple teams working on independent product domains

  • Release cycles vary by team

  • You want to scale development without rewriting everything

  • Stability and resilience matter

  • You want to test and deploy features independently

  • You want technology flexibility across teams

Micro frontends unlock long-term maintainability and organisational scalability.

2. Micro Frontend Architecture: The Big Picture

A typical micro frontend system includes:

  1. A shell (container) application

  2. Multiple micro frontend modules

  3. A communication mechanism

  4. A build and deployment strategy

  5. A shared design system (optional but recommended)

  6. Versioning and dependency governance

The Shell Application

The shell acts as the entry point of the system. Its responsibilities include:

  • Routing between micro frontends

  • Hosting shared dependencies

  • Bootstrapping the UI

  • Handling authentication and global state

  • Providing shared services (optional)

With Angular, this is often called the host or container application.

Micro Frontend Applications

Each micro frontend is responsible for:

  • Its own UI

  • Its own routing

  • Its own data management

  • Business logic for its domain

  • Independent deployments

A micro frontend must not depend on other micro frontends directly.

Integration Strategies

There are four dominant ways to integrate micro frontends:

  1. Build-time integration (bad)

  2. Server-side integration

  3. Iframe-based integration

  4. Runtime integration using Module Federation (modern and recommended)

Among these, Module Federation has become the de facto standard for micro frontends built using Angular, Webpack, or any modern frontend framework.

3. Angular + Module Federation: A Practical Approach

Angular 13+ introduced built-in support for Module Federation, which makes runtime integration smoother.

What Is Module Federation?

Module Federation is a Webpack feature (initially introduced with Webpack 5) that allows multiple independently built applications to load code from each other at runtime.

With Module Federation:

  • The shell can load Angular modules from remote applications

  • Micro frontends can expose specific modules

  • Each micro frontend can have its own Angular version (with caution)

  • No need to recompile or redeploy the shell when micro frontends update

How It Works

Every micro frontend defines:

  • Expose configuration

  • RemoteEntry.js file containing the exported modules

  • Angular module to expose

The shell defines:

  • Remote configuration pointing to each micro frontend

  • Lazy-loaded routes consuming the exposed modules

When the system runs:

  • The shell loads the remote modules on demand via HTTP

  • Angular bootstraps the micro application inside the shell

  • Routing behaves as if the micro frontend is part of the shell

4. Setting Up a Micro Frontend Architecture in Angular

Let’s go step-by-step with a production-grade example.

Assume we are building a scalable e-commerce platform with teams for:

  • Catalogue

  • Cart

  • Checkout

  • User Profile

We will build:

  • A shell (host) application

  • Four micro frontends

Create the Angular Workspace

Each application should ideally live in its own Git repository.
However, during development, you can start with a monorepo.

ng new ecommerce-shell --routing --style=scss
ng new ecommerce-catalogue --routing --style=scss
ng new ecommerce-cart --routing --style=scss
ng new ecommerce-checkout --routing --style=scss
ng new ecommerce-profile --routing --style=scss

Add Module Federation

Install the toolkit:

ng add @angular-architects/module-federation

This command updates the Webpack configuration and adds a basic module federation setup.

Configure the Shell

Example webpack.config.js for the shell:

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  output: {
    uniqueName: "ecommerceShell",
  },
  plugins: [
    new ModuleFederationPlugin({
      remotes: {
        catalogue: "catalogue@http://localhost:4201/remoteEntry.js",
        cart: "cart@http://localhost:4202/remoteEntry.js",
        checkout: "checkout@http://localhost:4203/remoteEntry.js",
        profile: "profile@http://localhost:4204/remoteEntry.js",
      },
      shared: {
        "@angular/core": { singleton: true, strictVersion: true },
        "@angular/common": { singleton: true, strictVersion: true },
        "@angular/router": { singleton: true, strictVersion: true }
      },
    }),
  ],
};

Configure a Micro Frontend

Example for Catalogue micro frontend:

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  output: {
    uniqueName: "catalogue",
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "catalogue",
      filename: "remoteEntry.js",
      exposes: {
        "./Module": "./src/app/catalogue/catalogue.module.ts",
      },
      shared: {
        "@angular/core": { singleton: true },
        "@angular/common": { singleton: true },
        "@angular/router": { singleton: true }
      },
    }),
  ],
};

Routing in the Shell

The shell application loads each micro frontend lazily:

const routes: Routes = [
  {
    path: 'catalogue',
    loadChildren: () =>
      loadRemoteModule({
        remoteName: 'catalogue',
        exposedModule: './Module'
      }).then(m => m.CatalogueModule)
  },
  {
    path: 'cart',
    loadChildren: () =>
      loadRemoteModule({
        remoteName: 'cart',
        exposedModule: './Module'
      }).then(m => m.CartModule)
  }
];

This gives clean runtime integration.

5. Managing Shared Dependencies Across Micro Frontends

The Shared Dependencies Problem

Without governance:

  • Teams upgrade Angular independently

  • Shared libraries become misaligned

  • Bundle size increases

  • Runtime version conflicts break the UI

Best Practices

  1. Use strictVersion for Angular packages.

  2. Maintain a shared dependency contract across teams.

  3. Use a central design system for UI components.

  4. Establish versioning guidelines for shared libraries.

Angular Version Compatibility

Module Federation allows different versions of Angular, but this should be avoided unless:

  • Teams have strong reasons

  • You can guarantee compatibility

  • You are ready to handle runtime mismatches

The safest approach is to maintain a uniform version across all micro frontends.

6. Communication Between Micro Frontends

Micro frontends must be loosely coupled. Direct service injection across boundaries is not recommended.

Valid Communication Methods

  1. URL-based communication
    Encode identifiers in the route or query params.
    This is the simplest and most stable approach.

  2. Custom events (browser-native)
    Suitable for parent-child communication inside the shell.

  3. Shared service via shell dependency
    Only when the service is stable and global (like Auth).

  4. Cross-application state management
    Only for limited use cases with clear governance.

Avoid

  • Direct Angular service injection between micro frontends

  • Shared mutable state

  • Synchronous coupling

  • Global event buses without versioning

7. Deployment Strategies

Independent Deployment Pipelines

Each micro frontend should:

  • Have its own CI/CD pipeline

  • Produce its own build artifact

  • Deploy to its own URL

The Shell Must Not Rebuild for Every Micro Frontend Release

The shell should only reference the remote entry URLs.

You must avoid:

  • Rebuilding the shell for micro frontend updates

  • Hardcoding versions in the shell

Self-Healing Deployments

Use:

  • Cache busting

  • Versioned remoteEntry files

  • Rollback support

8. Security and Authentication

The Shell Should Handle Authentication

Reasons:

  • Prevent duplicate implementations

  • Avoid inconsistent session logic

  • Prevent insecure micro frontends

Micro Frontends Use Tokens Provided by Shell

Options:

  • Pass tokens via localStorage

  • Use a shared Auth service exposed by shell

  • Use cookies (with secure, HttpOnly flags)

Route Guard Strategy

Use shell-based guards:

  • All protected routes go through shell-level checks

  • Micro frontends should not implement auth logic independently

9. Performance Considerations

When Micro Frontends Improve Performance

  • Parallel loading

  • Smaller independent bundles

  • Less re-rendering

  • Faster deployments

When They Hurt Performance

  • Too many remote loads

  • Overuse of shared dependencies

  • Fragmented UI leading to layout shifts

Solutions

  1. Use preloading strategies in the shell.

  2. Use shared libraries wisely.

  3. Cache remoteEntry files.

10. Real-World Best Practices

Start With Domain-Driven Boundaries

Each micro frontend should map to a self-contained business capability.

Avoid Over-Splitting

Micro frontends should be coarse-grained. Too many MFEs increase complexity.

Good example: Catalogue + Cart + Checkout + Profile
Bad example: Button micro frontend + Table micro frontend

Build a Strong Governance Model

Define:

  • Dependency rules

  • Angular version policy

  • Shared library update guidelines

  • Code quality expectations

Introduce Micro Frontends Gradually

Never rewrite the whole system into micro frontends at once.
Migrate module by module.

Monitoring

Use:

  • Application performance monitoring

  • Distributed logs

  • Error tracking per micro frontend

11. A Production Checklist

Before going live:

  1. Stable Angular versions across MFEs

  2. Central design system implemented

  3. Shell handles authentication

  4. Independent deployment pipelines configured

  5. RemoteEntry files versioned

  6. Routing tested for all MFEs

  7. Error handling implemented

  8. Performance benchmarks done

  9. Security tests completed

  10. Clear rollback strategy in place

12. Conclusion

Micro frontends offer a powerful way to scale frontend development in large organisations. They allow teams to work independently, release faster, and manage complexity with long-term sustainability. However, the architecture demands discipline, governance, and careful planning.

When implemented correctly with Angular and Module Federation, micro frontends provide:

  • Independent deployment

  • Domain isolation

  • Technology flexibility

  • Faster builds

  • Better team autonomy

In real-world production systems, success depends less on framework capabilities and more on strong engineering practices, clear boundaries, and consistent dependency management.

Micro frontends are not just a technical choice; they are an organisational strategy for scaling frontend teams responsibly.