lunx.docs
DocsTutorialsModule Federation

Module Federation

Build scalable micro-frontend architectures with Lunx's first-class Module Federation support. Share code, components, and state across independently deployed applications.

What is Module Federation?

Module Federation (MFE) allows multiple independently-deployed JavaScript applications to share code at runtime. With Lunx, you declare which modules each application exposes and which remotes it consumes — the Rust bundler handles everything else.

  • Shell / Host app — the main application that loads remote modules
  • Remote app — independently deployed app that exposes components or utilities
  • Shared modules — singletons like React that must have only one instance at runtime

Setting up a Host application

typescriptshell/lunx.config.ts
import { defineConfig } from 'lunx'

export default defineConfig({
  framework: 'react',
  server: { port: 3000 },
  federation: {
    name: 'shell',
    remotes: {
      // Name: 'remoteName@remoteEntry URL'
      auth:      'auth@http://localhost:3001/remoteEntry.js',
      dashboard: 'dashboard@http://localhost:3002/remoteEntry.js',
      profile:   'profile@http://localhost:3003/remoteEntry.js',
    },
    shared: {
      react:      { singleton: true, requiredVersion: '^18.0.0' },
      'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
      'react-router-dom': { singleton: true },
    },
  },
})

Setting up a Remote application

typescriptdashboard/lunx.config.ts
import { defineConfig } from 'lunx'

export default defineConfig({
  framework: 'react',
  server: { port: 3002 },
  federation: {
    name: 'dashboard',
    filename: 'remoteEntry.js',   // entry point consumed by host
    exposes: {
      // './LocalName': './path/to/component'
      './Widget':   './src/components/Widget.tsx',
      './StatCard': './src/components/StatCard.tsx',
      './useStats': './src/hooks/useStats.ts',
    },
    shared: {
      react:      { singleton: true, requiredVersion: '^18.0.0' },
      'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
    },
  },
})

Consuming a remote component

Use React.lazy to import remote components. Lunx resolves the dashboard/Widget import to the configured remote URL at build time.

typescriptshell/src/App.tsx
import { lazy, Suspense } from 'react'

// These are loaded from the remote application at runtime
const DashboardWidget  = lazy(() => import('dashboard/Widget'))
const DashboardStatCard = lazy(() => import('dashboard/StatCard'))

export default function App() {
  return (
    <div className="p-8">
      <h1>Shell Application</h1>
      <Suspense fallback={<div>Loading dashboard...</div>}>
        <DashboardWidget title="Revenue" value="$124,340" />
        <DashboardStatCard metric="Active Users" count={8_291} />
      </Suspense>
    </div>
  )
}

TypeScript type sharing

Lunx can generate TypeScript declaration files for all exposed modules, enabling full type safety across remote boundaries without manual type duplication.

typescriptdashboard/lunx.config.ts
export default defineConfig({
  framework: 'react',
  federation: {
    name: 'dashboard',
    exposes: { './Widget': './src/components/Widget.tsx' },
    // Generate .d.ts files for all exposed modules
    dts: { outputPath: './dist/types' },
  },
})
bash
# In the shell app, install the remote's types
npm install dashboard-app@http://localhost:3002/types.tgz

# Now imports are fully typed:
import type { WidgetProps } from 'dashboard/Widget'

Production deployment

Each micro-frontend is deployed independently. The host application only needs the URL of each remote's remoteEntry.js — update a remote without redeploying the host.

typescriptshell/lunx.config.ts
export default defineConfig(({ mode }) => ({
  framework: 'react',
  federation: {
    name: 'shell',
    remotes: {
      // Use environment variables for production URLs
      dashboard: `dashboard@${
        mode === 'production'
          ? 'https://dashboard.example.com/remoteEntry.js'
          : 'http://localhost:3002/remoteEntry.js'
      }`,
    },
  },
}))
Independent deployments
Each remote app has its own CI/CD pipeline and deploys independently. Teams own their micro-frontend end-to-end. The host app loads the latest version automatically — no coordinated release needed.
Singleton shared modules
Always mark react, react-dom, and routing libraries as { singleton: true }. Multiple React instances cause context failures and hooks to behave incorrectly. Lunx will warn you at startup if duplicates are detected.