npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vite-plugin-federation

v1.0.0

Published

A Vite plugin for Module Federation.

Readme

vite-plugin-federation

CI npm license

A production-ready GA Module Federation 2.0 plugin for Vite 5, 6, 7, and 8.

It is built around manifest-first remote loading, Node SSR, live DTS workflows, dev remote HMR, multi-tenant runtime scopes, and operational runtime controls. It also includes an OriginJS-compatible virtual:__federation__ migration shim for existing Vite federation apps.

vite-plugin-federation 1.0 is generally available for manifest-first Vite remotes, browser hosts, Node SSR hosts, DTS generation and consumption, dev remote HMR, and the curated runtime APIs. Webpack/SystemJS/var remotes are supported compatibility paths, but mixed migrations should be validated per application. Signed manifest verification is intentionally handled through a custom fetch wrapper so teams can use their own signing and trust model.

Install

pnpm add -D vite-plugin-federation
npm install -D vite-plugin-federation
yarn add -D vite-plugin-federation

Requirements:

  • Node >=20.19.0
  • Vite ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0

These ranges are the v1.x compatibility floor.

The package exports:

  • vite-plugin-federation: the Vite plugin.
  • vite-plugin-federation/runtime: runtime helpers for manifest loading, SSR, preload, integrity, diagnostics, and scoped runtimes.

Why Use It

| Need | What this package provides | | ------------------------------ | --------------------------------------------------------------------------------------------------------------- | | Vite 5 through Vite 8 | Rollup and Rolldown-aware output handling, including module-preload helper rewrites. | | Manifest-first federation | mf-manifest.json, mf-stats.json, and mf-debug.json outputs by default. | | Production host loading | Cache TTL, stale-while-revalidate, retries, timeouts, fallback URLs, request collapsing, and circuit breakers. | | Node SSR | ssrRemoteEntry, server runtime creation, target-aware manifest registration, and SSR preload link collection. | | Shared dependency control | Singleton diagnostics, strict singleton mode, version checks, host-only shares, and pnpm suffix matching. | | DTS workflows | Remote type archives, host type consumption, manifest-derived type URLs, and dev hot sync. | | Multi-tenant runtime isolation | Per-runtime-key manifest cache, breaker state, debug records, and load metrics. | | Migration | OriginJS-compatible virtual:__federation__ shim and legacy remote compatibility paths. |

Quick Start

Remote

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from 'vite-plugin-federation';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'catalog',
      exposes: {
        './Button': './src/Button.tsx',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^19.0.0' },
        'react/': { singleton: true, requiredVersion: '^19.0.0' },
      },
    }),
  ],
  build: {
    target: 'esnext',
  },
});

By default, a remote build emits:

  • remoteEntry-[hash].js
  • mf-manifest.json
  • mf-stats.json
  • mf-debug.json

Use a fixed remote entry name when your deployment needs one:

federation({
  name: 'catalog',
  filename: 'remoteEntry.js',
  exposes: {
    './Button': './src/Button.tsx',
  },
});

Browser Host

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from 'vite-plugin-federation';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'shell',
      remotes: {
        catalog: 'https://cdn.example.com/catalog/mf-manifest.json',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^19.0.0' },
        'react/': { singleton: true, requiredVersion: '^19.0.0' },
      },
    }),
  ],
  build: {
    target: 'esnext',
  },
});

Load a manifest remote explicitly:

import { lazy, Suspense } from 'react';
import { loadRemoteFromManifest } from 'vite-plugin-federation/runtime';

const catalogManifestUrl = 'https://cdn.example.com/catalog/mf-manifest.json';

const CatalogButton = lazy(async () => {
  const mod = await loadRemoteFromManifest('catalog/Button', catalogManifestUrl, {
    cacheTtl: 30_000,
    retries: 2,
    timeout: 4_000,
  });

  return { default: mod.default ?? mod };
});

export function App() {
  return (
    <Suspense fallback={null}>
      <CatalogButton />
    </Suspense>
  );
}

You can also use the classic Module Federation runtime style after remotes are registered:

import { loadRemote } from 'vite-plugin-federation/runtime';

const mod = await loadRemote('catalog/Button');

Node SSR Host

// vite.config.ts
import { defineConfig } from 'vite';
import federation from 'vite-plugin-federation';

export default defineConfig({
  plugins: [
    federation({
      name: 'ssr-shell',
      remotes: {
        catalog: 'https://cdn.example.com/catalog/mf-manifest.json',
      },
      target: 'node',
    }),
  ],
  build: {
    ssr: true,
    target: 'esnext',
  },
});
// server.ts
import {
  collectFederationManifestPreloadLinks,
  createServerFederationInstance,
  fetchFederationManifest,
  loadRemoteFromManifest,
} from 'vite-plugin-federation/runtime';

createServerFederationInstance({
  name: 'ssr-shell',
  remotes: [],
  shared: {},
});

const manifestUrl = process.env.CATALOG_MANIFEST_URL!;
const manifest = await fetchFederationManifest(manifestUrl, { cacheTtl: 30_000 });

const mod = await loadRemoteFromManifest('catalog/Button', manifestUrl, {
  target: 'node',
  timeout: 4_000,
});

const preloadLinks = collectFederationManifestPreloadLinks(manifestUrl, manifest, './Button');

Node SSR currently requires Node's VM ESM loader support:

node --experimental-vm-modules server.js

Do not accept tenant- or request-controlled manifest URLs directly in SSR. Treat a Node-target remote as server-executed code, and route all manifest URLs through an operator-controlled allowlist.

Plugin Configuration

import federation from 'vite-plugin-federation';

federation({
  name: 'shell',
  remotes: {},
  exposes: {},
  shared: {},
});

Common options:

| Option | Default | Description | | ------------------------ | ---------------------------- | ------------------------------------------------------------------------ | | name | Required | Public application/container name. | | filename | remoteEntry-[hash] | Browser remote entry filename. | | varFilename | None | Emits an additional var-style remote entry for legacy hosts. | | exposes | {} | Remote expose map. Keys usually start with ./. | | remotes | {} | Host remote map. Manifest URLs are recommended. | | shared | {} | Shared providers and consumers. | | manifest | true | Emits manifest, stats, and debug artifacts. | | dts | Auto for TypeScript projects | Type generation and consumption through @module-federation/dts-plugin. | | dev | Enabled | Devtools, type hints, live reload, hot types, and opt-in remote HMR. | | compat | true | OriginJS-compatible virtual federation shim. | | shareStrategy | version-first | Runtime shared provider selection. | | shareScope | default | Default share scope. | | publicPath | Vite base or auto | Public path used in generated manifest asset URLs. | | bundleAllCSS | false | Adds all CSS assets to every expose manifest entry. | | runtimePlugins | [] | Runtime plugin imports passed to Module Federation runtime init. | | target | Build target | web or node; SSR builds auto-detect node. | | hostInitInjectLocation | html | Inject host runtime initialization in HTML or entry. | | moduleParseTimeout | 10 | Total module parse timeout in seconds. | | moduleParseIdleTimeout | None | Idle parse timeout in seconds, reset after every parsed module. |

Exposes

federation({
  name: 'catalog',
  exposes: {
    './Button': './src/Button.tsx',
    './ManualCssButton': {
      import: './src/ManualCssButton.tsx',
      css: { inject: 'manual' },
    },
  },
});

CSS modes:

  • head: append CSS to document.head.
  • manual: write CSS hrefs to the global CSS bucket for the consumer to apply.
  • none: do not inject CSS.

dontAppendStylesToHead: true is accepted as an OriginJS-compatible alias for manual CSS handling.

Remotes

Prefer manifest URLs for new hosts:

federation({
  name: 'shell',
  remotes: {
    catalog: 'https://cdn.example.com/catalog/mf-manifest.json',
  },
});

Use object remotes for compatibility paths:

federation({
  name: 'shell',
  remotes: {
    legacy: {
      name: 'legacyRemote',
      entry: 'https://cdn.example.com/legacy/remoteEntry.js',
      entryGlobalName: 'legacyRemote',
      from: 'vite',
      format: 'esm',
      type: 'module',
      shareScope: 'default',
    },
  },
});

format: 'systemjs' expects globalThis.System.import at runtime. Browser CommonJS remotes are not part of the supported compatibility scope.

Shared Dependencies

federation({
  name: 'shell',
  shared: {
    react: {
      singleton: true,
      strictSingleton: true,
      requiredVersion: '^19.0.0',
      strictVersion: true,
      allowNodeModulesSuffixMatch: true,
    },
    'react/': {
      singleton: true,
      requiredVersion: '^19.0.0',
      allowNodeModulesSuffixMatch: true,
    },
    'design-system': {
      import: false,
      requiredVersion: '^2.0.0',
    },
  },
});

Notes:

  • Use trailing slash keys such as react/ or @scope/pkg/ for package subpaths.
  • Use allowNodeModulesSuffixMatch for pnpm or symlinked workspace layouts.
  • Use import: false for host-only shared modules. The host must provide the share; the remote will not bundle a fallback.
  • Use strictSingleton when singleton conflicts should fail instead of silently falling back.

DTS

federation({
  name: 'catalog',
  dts: {
    generateTypes: {
      abortOnError: true,
    },
    consumeTypes: {
      typesOnBuild: true,
      abortOnError: true,
    },
  },
});

In TypeScript projects, DTS support is enabled automatically unless dts: false is configured. Remote builds emit @mf-types.zip and per-expose .d.ts artifacts; hosts can discover type URLs from mf-manifest.json.

Dev HMR And Devtools

federation({
  name: 'shell',
  dev: {
    remoteHmr: true,
    devtools: true,
    disableLiveReload: true,
    disableHotTypesReload: false,
    disableDynamicRemoteTypeHints: false,
  },
});

Remote HMR is opt-in. Devtools and dynamic type hints are enabled by default in dev.

Dev servers expose:

  • /mf-manifest.json or your configured manifest path.
  • /mf-debug.json.
  • /remoteEntry.js or the configured filename.
  • /__mf_hmr when dev.remoteHmr: true.
  • /__mf_devtools unless dev.devtools: false.

Runtime API

Import runtime helpers from vite-plugin-federation/runtime:

import {
  clearFederationRuntimeCaches,
  collectFederationManifestExposeAssets,
  collectFederationManifestPreloadLinks,
  createFederationInstance,
  createFederationManifestPreloadPlan,
  createFederationRuntimeScope,
  createServerFederationInstance,
  fetchFederationManifest,
  getFederationDebugInfo,
  loadRemote,
  loadRemoteFromManifest,
  loadShare,
  loadShareSync,
  preloadRemote,
  refreshRemote,
  registerManifestRemote,
  registerManifestRemotes,
  registerPlugins,
  registerRemotes,
  registerShared,
  verifyFederationManifestAssets,
  warmFederationRemotes,
} from 'vite-plugin-federation/runtime';

The high-level production path is loadRemoteFromManifest():

const mod = await loadRemoteFromManifest('catalog/Button', catalogManifestUrl, {
  target: 'web',
  cacheTtl: 30_000,
  staleWhileRevalidate: true,
  fallbackUrls: [backupManifestUrl],
  retries: 2,
  retryDelay: 200,
  timeout: 4_000,
  circuitBreaker: {
    failureThreshold: 3,
    cooldownMs: 30_000,
  },
  integrity: { mode: 'prefer-integrity' },
  fetch,
  fetchInit: { credentials: 'include' },
  hooks: {
    manifestFetch: (event) => console.debug(event),
    remoteRegister: (event) => console.debug(event),
    remoteLoad: (event) => console.debug(event),
    remoteRefresh: (event) => console.debug(event),
  },
});

Runtime Scopes

Use runtime scopes when multiple tenants, experiments, or apps share one page:

import { createFederationRuntimeScope } from 'vite-plugin-federation/runtime';

const tenant = createFederationRuntimeScope('tenant-a');

await tenant.registerManifestRemote('catalog', tenantManifestUrl, {
  shareScope: 'tenant-a',
});

const mod = await tenant.loadRemoteFromManifest('catalog/Button', tenantManifestUrl);

Each scope partitions manifest cache, in-flight requests, remote registration records, circuit breaker state, load metrics, and debug snapshots.

Preload

import {
  createFederationManifestPreloadPlan,
  fetchFederationManifest,
  warmFederationRemotes,
} from 'vite-plugin-federation/runtime';

await warmFederationRemotes({
  catalog: {
    manifestUrl: catalogManifestUrl,
    preload: { resourceCategory: 'sync' },
  },
  checkout: {
    manifestUrl: checkoutManifestUrl,
    preload: false,
  },
});

const manifest = await fetchFederationManifest(catalogManifestUrl, { cacheTtl: 30_000 });
const plan = createFederationManifestPreloadPlan(
  catalogManifestUrl,
  manifest,
  {
    '/product/:id': './Button',
  },
  {
    asyncChunkPolicy: 'css',
  },
);

For SSR rendering, use collectFederationManifestPreloadLinks() to create deduped modulepreload and stylesheet descriptors.

Integrity And Authenticated Manifests

const mod = await loadRemoteFromManifest('catalog/Button', catalogManifestUrl, {
  integrity: { mode: 'both' },
  fetchInit: {
    credentials: 'include',
    headers: {
      Authorization: `Bearer ${token}`,
    },
  },
});

Integrity modes:

  • prefer-integrity: use SRI when present, otherwise use contentHash.
  • integrity: require SRI.
  • content-hash: require contentHash.
  • both: require both values when verifying annotated assets.

Use verifyFederationManifestAssets() when you need to verify expose and preload assets declared in the manifest:

await verifyFederationManifestAssets(catalogManifestUrl, manifest, {
  integrity: { mode: 'both' },
  requireIntegrity: true,
});

For signed manifests, verify the detached signature in a custom fetch wrapper before returning the Response to the runtime.

Diagnostics

import { getFederationDebugInfo } from 'vite-plugin-federation/runtime';

console.log(getFederationDebugInfo());

The debug snapshot includes:

  • Module Federation runtime instance state.
  • Registered remotes and shared providers.
  • Manifest cache entries and source URLs.
  • Manifest fetch timeline.
  • Integrity verification results.
  • Circuit breaker state.
  • Remote load metrics.
  • Shared resolution graph and singleton conflict diagnostics.

OriginJS Migration

The OriginJS-compatible virtual module is enabled by default:

import {
  __federation_method_ensure,
  __federation_method_getRemote,
  __federation_method_setRemote,
  __federation_method_unwrapDefault,
  __federation_method_wrapDefault,
} from 'virtual:__federation__';

Disable it after migration:

federation({
  name: 'shell',
  compat: {
    originjs: false,
    virtualFederationShim: false,
  },
});

Security Notes

  • Prefer manifest-first ESM remotes over legacy script injection paths.
  • Treat Node SSR remotes as server-executed code.
  • Do not pass user-controlled manifest URLs into SSR runtime helpers.
  • Use origin allowlists for manifest URLs, remote entries, CSP, and Trusted Types policies.
  • Use fetchInit or custom fetch for private manifests.
  • Verify SRI/content hashes for high-trust deployments.
  • Verify signed manifests outside the default runtime with a custom fetch wrapper.
  • Keep Webpack/SystemJS/var compatibility paths isolated if they need looser CSP.

Error Codes

| Code | Meaning | | --------- | ------------------------------------------------------------------ | | MFV-001 | Plugin configuration error. | | MFV-002 | Alias conflict between a shared key and another resolver. | | MFV-003 | Shared dependency miss, fallback, or strict-singleton conflict. | | MFV-004 | Manifest fetch or validation failure. | | MFV-005 | Missing expose or unsupported legacy remote format. | | MFV-006 | SSR remote entry missing for a Node-target load. | | MFV-007 | Dynamic import rewrite warning or unsupported legacy from value. |

Documentation

Examples

The repository includes E2E-backed examples for React, Vue, Svelte, Lit, SSR, DTS, shared negotiation, workspace shared dependencies, OriginJS migration, and Webpack/SystemJS compatibility:

https://github.com/jskits/vite-plugin-federation/tree/main/examples

License

MIT