Skip to main content

Module Federation Complete Guide: Micro-Frontends at Scale

Created: February 22, 2026 Larry Qu 3 min read

Introduction

Module Federation enables micro-frontend architectures by allowing applications to dynamically share code at runtime. This guide covers everything you need to build scalable micro-frontend systems.

What is Module Federation?

Module Federation allows JavaScript applications to:

  • Share code at runtime
  • Load remote components
  • Build independent deployments
  • Scale horizontally
graph TB
    subgraph "Host App"
        Host[Main Application]
    end
    
    subgraph "Remote Apps"
        Remote1[Checkout App]
        Remote2[Product App]
        Remote3[User App]
    end
    
    Host -->|load| Remote1
    Host -->|load| Remote2
    Host -->|load| Remote3

Configuration

Host Application

// webpack.config.js (host)
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  mode: 'development',
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      remotes: {
        checkout: 'checkout@http://localhost:3001/remoteEntry.js',
        products: 'products@http://localhost:3002/remoteEntry.js',
        user: 'user@http://localhost:3003/remoteEntry.js',
      },
      shared: ['react', 'react-dom'],
    }),
  ],
};

Remote Application

// webpack.config.js (remote - checkout app)
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'checkout',
      filename: 'remoteEntry.js',
      exposes: {
        './CheckoutPage': './src/CheckoutPage.jsx',
        './CheckoutButton': './src/components/Button.jsx',
      },
      shared: ['react', 'react-dom'],
    }),
  ],
};

Consuming Remotes

Dynamic Imports

// Host app - dynamically load remote
import { lazy, Suspense } from 'react';

const CheckoutPage = lazy(() => import('checkout/CheckoutPage'));

function App() {
  return (
    <Suspense fallback="Loading...">
      <CheckoutPage />
    </Suspense>
  );
}

Fallback Strategies

// Provide fallback when remote unavailable
const CheckoutPage = lazy(() => 
  import('checkout/CheckoutPage')
    .catch(() => import('./LocalCheckoutFallback'))
);

Shared Dependencies

Version Management

// webpack.config.js
new ModuleFederationPlugin({
  name: 'checkout',
  exposes: {
    './Cart': './src/Cart.jsx',
  },
  shared: {
    react: {
      singleton: true,
      requiredVersion: '^18.0.0',
      eager: false,
    },
    'react-dom': {
      singleton: true,
      requiredVersion: '^18.0.0',
    },
    lodash: {
      eager: true, // Load immediately
    },
  },
});

Singleton Pattern

// Use singleton for hooks
new ModuleFederationPlugin({
  shared: {
    '@scope/shared-lib': {
      singleton: true,
      eager: true,
      requiredVersion: '^1.0.0',
    },
  },
});

State Management

Shared State

// Store in host
import { createContext } from 'react';

export const SharedContext = createContext(null);

// Provide in host app
function App() {
  return (
    <SharedContext.Provider value={globalState}>
      <Router>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/checkout" element={<CheckoutRemote />} />
        </Routes>
      </Router>
    </SharedContext.Provider>
  );
}

CSS Isolation

Scoped Styles

// Use CSS Modules in remotes
// checkout/src/Checkout.module.css
.checkoutContainer {
  padding: 20px;
}

// checkout/src/Checkout.jsx
import styles from './Checkout.module.css';

export function Checkout() {
  return <div className={styles.checkoutContainer}>...</div>;
}

Shadow DOM

// For complete isolation, use Shadow DOM
const RemoteWrapper = ({ children }) => {
  const shadowRoot = useRef(null);
  
  if (!shadowRoot.current) {
    shadowRoot.current = shadowRoot.attachShadow({ mode: 'open' });
  }
  
  return (
    <div ref={shadowRoot}>
      {children}
    </div>
  );
};

Build & Deployment

Independent Builds

// Each app has own build
// checkout/webpack.config.js
// products/webpack.config.js
// user/webpack.config.js

// Deploy independently
// checkout: deploy to s3://checkout.example.com
// products: deploy to s3://products.example.com

CI/CD Pipeline

# .github/workflows/deploy.yml
jobs:
  deploy-checkout:
    runs-on: checkout
    steps:
      - uses: actions/checkout@v4
      - run: npm install
      - run: npm run build
      - run: npm run deploy
      
  deploy-products:
    runs-on: products
    # Independent deployment

Use Cases

E-commerce

// Host: main-storefront.com
// Remote: checkout, products, user, search

Dashboard

// Host: dashboard.com
// Remote: analytics, reports, settings, notifications

Best Practices

1. Version Alignment

// Keep shared dependencies in sync across all apps
// Use package.json resolutions or workspaces

2. Error Boundaries

class ErrorBoundary extends React.Component {
  componentDidCatch(error) {
    // Log and show fallback
  }
  
  render() {
    return this.props.children;
  }
}

3. Type Sharing

// Share TypeScript types between apps
// Use npm workspace or git submodule for shared types

Conclusion

Module Federation enables:

  • Independent deployments
  • Code sharing at runtime
  • Scalable architectures
  • Team autonomy

Perfect for: Large applications, multiple teams, e-commerce, dashboards.


External Resources

Resources

Comments

Share this article

Scan to read on mobile