Skip to content

Monolithic vs Micro-Frontend Builds — Complete Architecture Comparison

DodaTech Updated 2026-06-23 7 min read

In this tutorial, you'll learn about Monolithic vs Micro. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Monolithic frontends build a single deployable unit from one codebase, while micro-frontends decompose the user interface into independently built, deployed, and versioned modules that integrate at runtime through composition techniques.

What You'll Learn

You'll learn the architectural differences between monolith and micro-frontend builds, how each approach affects team organization, deployment pipelines, shared dependency management, and performance characteristics with real benchmarks.

Why This Comparison Matters

As frontend applications grow, teams face a choice between maintaining a single large codebase or splitting into smaller, autonomous modules. The wrong choice leads to slow build pipelines, deployment bottlenecks, and team coordination overhead that scales non-linearly.

Real-World Use

The Doda Browser extensions marketplace transitioned from a monolithic React app to a micro-frontend architecture, allowing five independent teams to deploy their sections (search, themes, security, updates, developer tools) on separate schedules without coordinated releases.

Prerequisites

  • React, Angular, or Vue experience
  • Understanding of Webpack or Vite build configurations
  • Familiarity with Docker and CI/CD concepts

Step 1: Monolithic Frontend Build

A monolith frontend compiles all modules into a single bundle. One package.json, one build configuration, one deployment artifact.

// Monolith webpack.config.js
const path = require('path');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
  },
  module: {
    rules: [
      { test: /\.jsx?$/, loader: 'babel-loader' },
      { test: /\.css$/, use: ['style-loader', 'css-loader'] },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' }),
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors' },
      },
    },
  },
};
# Monolith CI pipeline — single build, single deploy
npm ci
npm run build
aws s3 sync dist/ s3://myapp-bucket/
aws cloudfront create-invalidation --paths "/*"

Expected behavior: All code — header, footer, dashboard, settings — compiles into one bundle. A single deployment updates everything simultaneously. Build time scales linearly with total codebase size.

Step 2: Micro-Frontend with Module Federation

Webpack 5's Module Federation allows separate builds to share and consume remote modules at runtime.

// Host application webpack.config.js (shell)
const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
  name: 'shell',
  remotes: {
    dashboard: 'dashboard@https://cdn.example.com/dashboard/remoteEntry.js',
    settings: 'settings@https://cdn.example.com/settings/remoteEntry.js',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
    'react-dom': { singleton: true },
  },
});
// Remote application webpack.config.js (dashboard micro-frontend)
const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
  name: 'dashboard',
  filename: 'remoteEntry.js',
  exposes: {
    './Dashboard': './src/Dashboard',
    './Widget': './src/Widget',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
    'react-dom': { singleton: true },
  },
});
// Shell imports remote components
const Dashboard = React.lazy(() => import('dashboard/Dashboard'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Dashboard />
    </Suspense>
  );
}

Expected behavior: The shell loads remoteEntry.js from each micro-frontend at runtime, fetching only the chunks needed for the current route. Each micro-frontend can be built and deployed independently.

Step 3: Shared Dependency Strategy

Micro-frontends sharing libraries like React must agree on a single version to avoid multiple React instances in the DOM.

// Shared dependency configuration for Module Federation
shared: {
  react: {
    singleton: true,
    requiredVersion: '^18.0.0',
    eager: false,
  },
  'react-dom': {
    singleton: true,
    requiredVersion: '^18.0.0',
  },
  'react-router-dom': {
    singleton: true,
    requiredVersion: '^6.0.0',
  },
  // Libraries that can have multiple versions
  'chart.js': {
    singleton: false, // Allow multiple versions
  },
}
# Independent deployment pipelines
# Team Dashboard
cd apps/dashboard
npm ci && npm run build
aws s3 sync dist/ s3://mf-dashboard/

# Team Settings
cd apps/settings
npm ci && npm run build
aws s3 sync dist/ s3://mf-settings/

# Team Shell — update remote URLs and deploy
cd apps/shell
npm ci && npm run build
aws s3 sync dist/ s3://mf-shell/

Expected behavior: Team Dashboard deploys a new version without affecting the Settings micro-frontend. The shell automatically loads the latest remoteEntry.js from each team's CDN path.

Step 4: Performance Comparison

Measure the real-world impact of each architecture.

# Measure monolith build time
cd monolith && time npm run build
# Output: npm run build  45.2s user 3.1s system 120% cpu 40.1 total

# Measure micro-frontend combined build time (parallel)
cd micro-frontends && time npm run build:all -- --parallel
# Output: npm run build:all  12.3s user 0.8s system 340% cpu 3.8 total

Expected benchmarks for a 200-page application:

Metric Monolith Micro-Frontends
Full build time 45 seconds 4 seconds per team (parallel)
Initial bundle size 1.2 MB 180 KB (shell only)
Lazy-loaded chunk 1.2 MB total 120 KB per micro-frontend
Deployment time 3 minutes 30 seconds per team
Team coordination Full regression test Independent per team
Shared library version One version enforced Per-team choice with singletons

Architecture

flowchart LR
    subgraph "Monolith"
        M1[src/pages/]
        M2[src/components/]
        M3[src/utils/]
        M4[webpack.config.js]
        M5[dist/bundle.js]
        M1 --> M5
        M2 --> M5
        M3 --> M5
        M4 --> M5
    end
    subgraph "Micro-Frontends"
        S[Shell
Host Container] D[Dashboard MF
remoteEntry.js] ST[Settings MF
remoteEntry.js] P[Profile MF
remoteEntry.js] S -->|loads| D S -->|loads| ST S -->|loads| P end

Common Errors

1. Multiple React instances detected When shared dependencies lack Singleton: true, each micro-frontend loads its own React copy. This causes broken hooks and context issues. Verify shared configuration and check network tab for duplicate React bundles.

2. Remote entry not found at runtime The shell cannot fetch the remote's remoteEntry.js. Causes include CORS Misconfiguration on the CDN, incorrect URL in remotes, or the remote not being deployed yet.

3. Version mismatch in shared singletons If one micro-frontend requires React 18 and another requires React 19, the Singleton negotiation fails. Align shared library versions across teams or use requiredVersion with a range.

4. CSS leakage between micro-frontends Styles from one micro-frontend affect another. Use CSS Modules, Shadow Dom, or scoped styles (styled-components, CSS-in-JS) to isolate styles per micro-frontend.

5. Route conflicts across micro-frontends Two micro-frontends register the same route. Define a global routing convention or have the shell manage top-level routing and delegate sub-routes to each micro-frontend.

Practice Questions

1. What is the main advantage of micro-frontends for large teams? Independent deployability — each team builds, tests, and deploys their micro-frontend without coordinating with other teams. This removes deployment bottlenecks and accelerates release cycles.

2. How does Module Federation share libraries at runtime? The shell negotiates shared library versions using a Singleton strategy. The first micro-frontend to load a library sets the version; subsequent micro-frontends reuse it or fail if the version requirement is incompatible.

3. What is a common performance cost of micro-frontends? Multiple network requests for separate bundles increase initial load time. Each micro-frontend has its own remoteEntry.js and chunks. Code Splitting within each micro-frontend and prefetching critical paths mitigate this.

4. Challenge: Build a micro-frontend shell Create a React shell application that loads two micro-frontends via Module Federation. One micro-frontend exposes a header component, the other a footer. Ensure shared React is a Singleton.

5. Challenge: Measure bundle overlap Build the same application as a monolith and as micro-frontends. Compare the total bytes transferred for the initial page load and identify any duplicated dependencies.

FAQ

When should you choose a monolith over micro-frontends?

Choose a monolith for small teams, early-stage products, or applications where deployment coordination is not a bottleneck. Micro-frontends add infrastructure and complexity that is not justified until team size and deployment frequency demand it.

Is Module Federation the only way to build micro-frontends?

No. Alternatives include iframes, Web Components, server-side composition (SSI, Tailor), and build-time integration with Monorepo tools like Nx and Turborepo.

Do micro-frontends require a separate domain or CDN?

Each micro-frontend needs a URL where its remoteEntry.js is served. They can share the same domain under different paths or use separate subdomains with proper CORS headers.

Next Steps

  • Learn Webpack Module Federation in depth with advanced configuration
  • Explore React component composition patterns for micro-frontends
  • Study the monorepo build tools guide for orchestrating micro-frontend builds
  • Review the Docker container build strategies for micro-frontend deployment

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro