Modern enterprise applications are growing in size and complexity. As teams scale and features evolve independently, a single monolithic frontend becomes difficult to maintain and deploy.
Micro Frontends (MFEs) offer a scalable solution by breaking large applications into smaller, independently deployable units each owned by separate teams.

With Webpack 5 Module Federation, Angular now provides a native and efficient way to implement Micro Frontends without complex runtime integrations.

This article explains how Module Federation works in Angular, its benefits, and a step-by-step implementation guide for integrating multiple micro frontends within a single shell application.

1. Understanding Micro Frontends

A Micro Frontend Architecture divides a large web application into multiple independent applications — or micro apps — that can:

Each micro frontend (MFE) handles a specific domain, such as:

These are then composed dynamically by a Shell (Host) application.

2. What is Module Federation?

Module Federation (introduced in Webpack 5) allows multiple applications to share code and load remote modules dynamically at runtime.

Key Concepts

3. Setting Up the Environment

Prerequisites

Step 1: Install the Module Federation Plugin

npm install @angular-architects/module-federation --save-dev

4. Creating the Applications

Step 2: Generate the Shell and Micro Frontends

ng new mfe-shell --routing --style=scss
ng new mfe-orders --routing --style=scss
ng new mfe-inventory --routing --style=scss

Each app runs independently at first.

5. Configuring Module Federation

Step 3: Configure the Host (Shell)

Navigate to the shell app and run:

ng add @angular-architects/module-federation --project mfe-shell --type host

This creates a webpack.config.js with placeholders to load remote apps.

Example configuration:

// mfe-shell/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const mf = require('@angular-architects/module-federation/webpack');

module.exports = {
  output: {
    uniqueName: "mfeShell",
    publicPath: "auto",
  },
  plugins: [
    new ModuleFederationPlugin({
      remotes: {
        "mfeOrders": "mfeOrders@http://localhost:4201/remoteEntry.js",
        "mfeInventory": "mfeInventory@http://localhost:4202/remoteEntry.js",
      },
      shared: mf.share({
        "@angular/core": { singleton: true, strictVersion: true },
        "@angular/common": { singleton: true, strictVersion: true },
        "@angular/router": { singleton: true, strictVersion: true },
      }),
    }),
  ],
};

Step 4: Configure a Remote Application

For the mfe-orders app:

ng add @angular-architects/module-federation --project mfe-orders --type remote --port 4201

Generated webpack.config.js example:

new ModuleFederationPlugin({
  name: "mfeOrders",
  filename: "remoteEntry.js",
  exposes: {
    "./OrdersModule": "./src/app/orders/orders.module.ts",
  },
  shared: mf.share({
    "@angular/core": { singleton: true, strictVersion: true },
    "@angular/common": { singleton: true, strictVersion: true },
    "@angular/router": { singleton: true, strictVersion: true },
  }),
}),

Do the same for mfe-inventory (on port 4202).

6. Consuming Remote Modules in the Shell

In the shell’s routing configuration:

const routes: Routes = [
  {
    path: 'orders',
    loadChildren: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4201/remoteEntry.js',
        exposedModule: './OrdersModule',
      }).then(m => m.OrdersModule),
  },
  {
    path: 'inventory',
    loadChildren: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4202/remoteEntry.js',
        exposedModule: './InventoryModule',
      }).then(m => m.InventoryModule),
  },
];

Now, navigating to /orders or /inventory in the shell dynamically loads the respective remote application.

7. Sharing Common Libraries

To reduce bundle size and maintain consistency:

You can modify webpack.config.js in each project:

shared: mf.share({
  "@angular/core": { singleton: true, strictVersion: true },
  "@angular/common": { singleton: true, strictVersion: true },
  "@angular/router": { singleton: true, strictVersion: true },
  "shared-lib": { singleton: true, import: "shared-lib" },
}),

8. Running and Testing

Start all apps in separate terminals:

ng serve mfe-orders --port 4201
ng serve mfe-inventory --port 4202
ng serve mfe-shell --port 4200

Open

http://localhost:4200/orders
http://localhost:4200/inventory

You’ll notice the shell dynamically loads content from the micro frontends.

9. Deployment and Versioning

Each MFE can:

The shell always loads the latest version at runtime — no redeployment required for the entire app.

10. Advantages of Using Module Federation in Angular

11. Real-World Use Cases

12. Conclusion

Integrating Micro Frontends using Module Federation in Angular provides a robust foundation for building scalable, modular, and future-proof enterprise applications.

By combining independent deployability with shared runtime integration, Module Federation eliminates the pain of monolithic frontends and empowers teams to innovate faster without sacrificing consistency or maintainability.