> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Getting Started

To use Module Federation in Modern.js, we recommend using the official plugin `@module-federation/modern-js-v3`.

This section will introduce how to set up both producer and consumer applications using the official plugin. First, create two applications by following the [Modern.js Quick Start](/guides/get-started/quick-start.md).

## Install the Plugin

After creating the applications, install the plugin for both projects:


```sh [npm]
npm add @module-federation/modern-js-v3
```

```sh [yarn]
yarn add @module-federation/modern-js-v3
```

```sh [pnpm]
pnpm add @module-federation/modern-js-v3
```

```sh [bun]
bun add @module-federation/modern-js-v3
```

```sh [deno]
deno add npm:@module-federation/modern-js-v3
```

## Register the Plugin

After installing the plugin, you need to register it in the `modern.config.js` file:

```ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js-v3';

export default defineConfig({
  plugins: [appTools(), moduleFederationPlugin()],
});
```

## Export Modules from Producer

Next, modify the producer's code to export the Module Federation module.

Create the `src/components/Button.tsx` file and export a Button component:

```tsx title="src/components/Button.tsx"
import React from 'react';

export const Button = () => {
  return <button type="button">Remote Button</button>;
};
```

Then, add the `module-federation.config.ts` file at the project root to configure the Module Federation module's name, shared dependencies, and exports:

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';

export default createModuleFederationConfig({
  name: 'remote',
  manifest: {
    filePath: 'static',
  },
  filename: 'static/remoteEntry.js',
  exposes: {
    './Button': './src/components/Button.tsx',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
});
```

:::tip
In the above code block, we have prefixed both the manifest and remoteEntry.js exported by Module Federation with `static`. This is because Modern.js requires all resources that need to be exposed to be placed in the `static/` directory, and Modern.js's server will only host the `static/` directory in production environments.
:::

Additionally, modify `modern.config.ts` to provide a development environment port for the producer, allowing the consumer to access the producer's resources through this port:

```ts title="modern.config.ts"
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js-v3';

export default defineConfig({
  server: {
    port: 3051,
  },
  plugins: [appTools(), moduleFederationPlugin()],
});
```

## Use Modules in Consumer

Now, modify the consumer's code to use the module exported by the producer.

Add the `module-federation.config.ts` file at the project root to configure the Module Federation module's name, shared dependencies, and the remote module to use:

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';

export default createModuleFederationConfig({
  name: 'host',
  remotes: {
    remote: 'remote@http://localhost:3051/static/mf-manifest.json',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
});
```

`mf-manifest.json` is the file produced by the producer after packaging, containing all the information about the modules exported by the producer.

Create a new route file `src/routes/remote/page.tsx` and import the producer module:

```tsx title="src/routes/remote/page.tsx"
import React, { Suspense, type JSX } from 'react';
import { Button } from 'remote/Button';

const Index = (): JSX.Element => {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <Button />
      </Suspense>
    </div>
  );
};

export default Index;
```

At this point, importing `remote/Button` will result in a type error because the local environment doesn't have the type for the remote module. Module Federation 2.0 provides [type hints](https://module-federation.io/zh/guide/basic/type-prompt.html), which will automatically generate type definitions for remote modules during the producer's build and download them during the consumer's build.

To ensure the types take effect, add a new `path` in `tsconfig.json`:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "paths": {
      "*": ["./@mf-types/*"]
    }
  }
}
```

:::tip
In the consumer, we reference the remote module using `remote/Button`. Here's a brief explanation of what this path specifically represents. You can abstract it as `[remoteAlias]/[remoteExpose]`.

The first part, `remoteAlias`, is the alias of the producer in the consumer. It is the `key` configured in the `remotes` field of the consumer's `module-federation.config.ts`:

```ts
{
  remotes: {
    [remoteAlias]: '[remoteModuleName]@[URL_ADDRESS]',
  }
}
```

Here, we also abstract the remote address as `[remoteModuleName]@[URL_ADDRESS]`. The part before `@` must correspond to the module name of the producer.

The second part, `remoteExpose`, is the `key` configured in the `exposes` field of the producer's `module-federation.config.ts`.
:::

## Start the Applications

Now, both the producer and consumer applications are set up. You can run `modern dev` locally to start both applications.

Once started, the imports of the producer's modules in the consumer will no longer throw errors, and the types will be downloaded to the consumer application.

:::note
After modifying the producer's code, the consumer will automatically fetch the producer's types.
:::

Access `http://localhost:8080/remote`, and you will see that the page includes the `Button` component from the producer's remote module.

We can also execute `modern serve` locally to simulate the production environment.

Because the Module Federation plugin will automatically read Modern.js's `output.assetPrefix` configuration as the access address for remote modules, and this value defaults to `/` after building in the production environment.

If we want to simulate the production environment in local, but not configure `output.assetPrefix`, consumers will pull the entry file of the remote module from their own domain. So We can add the following configuration:

```ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js-v3';

// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
  server: {
    port: 3051,
  },
  output: {
    // Now this configuration is only used in the local when you run modern serve command.
    // If you want to deploy the application to the platform, use your own domain name.
    // Module federation will automatically write it to mf-manifest.json, which influences consumer to fetch remoteEntry.js.
    assetPrefix: 'http://127.0.0.1:3051',
  },
  plugins: [appTools(), moduleFederationPlugin()],
});
```

Now, in the producer, run `modern build && MODERN_MF_AUTO_CORS=true  modern serve`, and in the consumer, run `modern build && modern serve` to simulate the production environment locally and access the remote modules.

:::tip
When using the `modern serve` command, you need to set the `MODERN_MF_AUTO_CORS=true` environment variable when starting the producer project to automatically handle CORS issues and ensure that consumers can properly access the producer's remote module resources.
:::

You can refer to this example: [Modern.js & Module Federation Basic Example](https://github.com/web-infra-dev/modern.js/tree/main/examples/module-federation/base).

## Related Documentation

- [Module Federation Official Documentation](https://module-federation.io/zh/guide/framework/modernjs.html)
