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

# Static Site Generation

SSG (Static Site Generation) is a technical solution that generates complete static web pages at build time based on data and templates. This means that in a production environment, pages are pre-rendered with content and can be cached by a CDN. SSG can offer better performance and higher security for pages that do not require dynamic data.

## Enabling SSG

To enable SSG functionality in a Modern.js project, follow these steps to modify the code:

1. Install SSG plugin dependencies

If the SSG plugin is not yet installed in your project, install it first:

```bash
pnpm add @modern-js/plugin-ssg
```

:::tip Version Consistency

Make sure the version of `@modern-js/plugin-ssg` matches the version of `@modern-js/app-tools` in your project. All Modern.js official packages are released with a uniform version number, and version mismatches may cause compatibility issues.

Check the version of `@modern-js/app-tools` first, then install the same version of `@modern-js/plugin-ssg`:

```bash
# Check the current version of @modern-js/app-tools
pnpm list @modern-js/app-tools

# Install the same version of @modern-js/plugin-ssg
pnpm add @modern-js/plugin-ssg@<version>
```

:::

2. Configure modern.config.ts

Import and add the SSG plugin in the `modern.config.ts` file, and configure `output.ssg`:

```ts title="modern.config.ts"
import { defineConfig, appTools } from '@modern-js/app-tools';
import { ssgPlugin } from '@modern-js/plugin-ssg';

export default defineConfig({
  plugins: [appTools(), ssgPlugin()],
  output: {
    ssg: true,
  },
});
```

:::info Scope of Application

- Use `output.ssg` for single-entry apps.
- Use `output.ssgByEntries` for multi-entry apps.
- When only `output.ssg: true` is set and `output.ssgByEntries` is not configured, all routes under all entries will be treated as SSG routes.

:::

## Development Debugging

Since SSG also renders pages in a Node.js environment, we can enable SSR during the **development phase** to expose code issues early and validate the SSG rendering effect:

```ts title="modern.config.ts"
export default defineConfig({
  server: {
    ssr: process.env.NODE_ENV === 'development',
  }
}
```

## Using SSG in Conventional Routing

In **conventional routing**, Modern.js generates routes based on the file structure under the entry point, allowing the framework to collect complete route information.

### Basic Usage

For example, the following is a project directory structure using conventional routing:

```bash
.
└── routes
    ├── layout.tsx
    ├── page.tsx
    └── user
        ├── layout.tsx
        ├── page.tsx
        └── profile
            └── page.tsx
```

The above file directory will generate the following three routes:

- `/`
- `/user`
- `/user/profile`

:::tip
If you are not familiar with the rules of conventional routing, refer to the [Routing Solution](/guides/basic-features/routes/routes.md) first.

:::

Add component code in `src/routes/page.tsx`:

```jsx title="src/routes/page.tsx"
export default () => {
  return <div>Index Page</div>;
};
```

Run the command `pnpm run dev` at the project root and check the `dist/` directory, where only one HTML file `main/index.html` is generated.

Run the command `pnpm run build` at the project root, and after the build completes, check the `dist/` directory again. This time, you'll find `main/index.html`, `main/user/index.html`, and `main/user/profile/index.html` files, each corresponding to the routes listed above.

Each route in **conventional routing** will generate a separate HTML file. Checking `main/index.html`, you will find it contains the text `Index Page`, which demonstrates the effect of SSG.

After running `pnpm run serve` to start the project, inspect the returned document in the Network tab of the browser's development tools. The document includes the fully rendered content from the component.

## Using SSG in Manual Routing

**Manual routing** defines routes through component code, requiring the application to run to obtain accurate route information. Therefore, you cannot use the SSG feature out of the box. Developers need to configure which routes require SSG.

For example, consider the following code with multiple routes. By setting `output.ssg` to `true`, it will only render the entry route (`/`) by default.

```tsx title="src/App.tsx"
import { BrowserRouter, Route, Routes } from '@modern-js/runtime/router';
import { StaticRouter } from '@modern-js/runtime/router/server';
import { use } from 'react';
import { RuntimeContext } from '@modern-js/runtime';

const Router = typeof window === 'undefined' ? StaticRouter : BrowserRouter;

export default () => {
  const context = use(RuntimeContext);
  const pathname = context?.request?.pathname;
  return (
    <Router location={pathname}>
      <Routes>
        <Route index element={<div>index</div>} />
        <Route path="about" element={<div>about</div>} />
      </Routes>
    </Router>
  );
};
```

If you want to enable SSG for `/about` as well, you can configure `output.ssg`:

```ts title="modern.config.ts"
export default defineConfig({
  output: {
    ssg: {
      routes: ['/', '/about'],
    },
  },
});
```

After running `pnpm run build`, you will see a new `main/about/index.html` file in the `dist/` directory.

After running `pnpm run serve` to start the project, inspect the returned document in the Network tab of the browser's development tools. The document includes the fully rendered content from the component.

:::info
The above example introduces single-entry scenarios. For more information, refer to the [API Documentation](/configure/app/output/ssg.md).
:::

## Adding Dynamic Routes

In manual routing or conventional routing with dynamic segments (e.g., `/user/[id]`), provide concrete paths directly in `routes`.

```js
export default defineConfig({
  output: {
    ssg: {
      routes: ['/', '/about', '/user/modernjs'],
    },
  },
});
```

## Multi-entry

For multi-entry apps, configure per entry via `output.ssgByEntries`:

```js
export default defineConfig({
  output: {
    ssgByEntries: {
      home: {
        routes: ['/', '/about', '/user/modernjs'],
      },
      admin: false,
    },
  },
});
```

:::info
See API details: [output.ssgByEntries](/configure/app/output/ssgByEntries.md)
:::

## Configuring Request Headers for Rendering

Modern.js supports configuring request headers for specific entries or routes. For example:

```js
export default defineConfig({
  output: {
    ssg: {
      headers: {
        'x-tt-env': 'ppe_modernjs',
      },
      routes: [
        '/',
        {
          url: '/about',
          headers: {
            from: 'modern-website',
          },
        },
      ],
    },
  },
});
```

In the above configuration, the `x-tt-env` request header is set for all routes, and the `from` request header is specifically set for the `/about` route.

:::tip
Headers set in routes will override headers set for entries.
:::
