zudo-doc supports maintaining multiple versions of your documentation side by side. When versioning is enabled, older (or pre-release) versions are served under version-prefixed URLs, and a version switcher appears in the layout for users to navigate between versions.

## Overview

Versioning lets you:

- Keep the **latest** documentation at `/docs/...` as usual
- Serve older versions at `/v/{version}/docs/...`
- Show a **version switcher** so users can navigate between versions
- Display **version banners** to indicate outdated or unreleased content

## Enabling Versioning

Versioning is **disabled by default**. To enable it, add a `versions` array to `zudoDoc({...})` in `zfb.config.ts`:

```ts title="zfb.config.ts"
export default defineConfig(
  zudoDoc({
    // ...
    versions: [
      {
        slug: "1.0",
        label: "1.0.0",
        docsDir: "src/content/docs-v1",
        locales: {
          ja: { dir: "src/content/docs-v1-ja" },
          de: { dir: "src/content/docs-v1-de" },
        },
        banner: "unmaintained",
      },
    ],
  }),
);
```

Set `versions` to `false` (or omit it) to disable versioning:

```ts
versions: false,
```

## Configuration Reference

Each version entry accepts the following properties:

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `slug` | string | Yes | Version identifier used in URL paths (e.g., `"1.0"`, `"v2"`) |
| `label` | string | Yes | Display label shown in the version switcher (e.g., `"1.0.0"`) |
| `docsDir` | string | Yes | Content directory for this version's English docs |
| `locales` | `Record<string, { dir: string }>` | No | Per-locale content directories; each entry takes only `{ dir }` (no `label`) |
| `banner` | `"unmaintained"` \| `"unreleased"` \| `false` | No | Banner type displayed on versioned pages |

## Directory Structure

Each version's content lives in its own directory. The latest (current) version uses the default `docsDir`, while older versions use the directories specified in their configuration:

```
src/content/
├── docs/                # Latest version (default)
├── docs-ja/             # Latest version — Japanese
├── docs-de/             # Latest version — German (if configured)
├── docs-v1/             # Version 1.0 — English
├── docs-v1-ja/          # Version 1.0 — Japanese
├── docs-v1-de/          # Version 1.0 — German (if configured)
├── docs-v0.9/           # Version 0.9 — English
├── docs-v0.9-ja/        # Version 0.9 — Japanese
└── docs-v0.9-de/        # Version 0.9 — German (if configured)
```

[Dynamic content unavailable in text export]

Each version directory must exist and contain valid MDX content files. zudo-doc creates a separate zfb content collection for each version, so missing directories will cause build errors.



## URL Structure

The latest version is served at the default docs URL. Older versions use a `/v/{slug}/` prefix:

- **Latest:** `/docs/getting-started/introduction/`
- **Version 1.0:** `/v/1.0/docs/getting-started/introduction/`
- **Version 0.9:** `/v/0.9/docs/getting-started/introduction/`

With locales, the locale prefix comes after the version prefix:

- **Latest (Japanese):** `/ja/docs/getting-started/introduction/`
- **Version 1.0 (Japanese):** `/v/1.0/ja/docs/getting-started/introduction/`
- **Version 1.0 (German):** `/v/1.0/de/docs/getting-started/introduction/`

## Version Switcher

When one or more versions are configured, a **version switcher** automatically appears in both the header bar and the doc content area. It displays the current version label and provides links to switch between all available versions, including the latest.

The switcher preserves the current page slug when navigating between versions, so users land on the same topic in the selected version.

If a page does not exist in an older version, that version's link is automatically **disabled** (greyed out and not clickable) instead of linking to a 404 page. This is determined at build time by scanning each version's content directory.

The dropdown also includes an **"All versions"** link at the bottom, which navigates to the [versions listing page](/docs/versions/).

## Versions Listing Page

A dedicated versions page is automatically generated at `/docs/versions/` (and `/ja/docs/versions/` for Japanese). This page lists all configured versions with their labels, status badges, and documentation links — similar to [Docusaurus' versions page](https://docusaurus.io/versions).

The page is auto-generated from the `versions` array you pass to `zudoDoc({...})`. No manual maintenance is needed — adding or removing versions in the configuration automatically updates the listing page.

Each version's documentation link (and the "latest docs" link) points at the route slug configured by `entryDocSlug`:

```ts title="zfb.config.ts"
export default defineConfig(
  zudoDoc({
    // ...
    entryDocSlug: "getting-started",
  }),
);
```

`entryDocSlug` is a route slug with no leading or trailing slashes — e.g. `"getting-started"` or `"overview/getting-started"`. It defaults to `"getting-started"` when omitted, and is not validated at runtime: pointing it at a slug that doesn't exist simply produces a 404 link rather than failing the build.

## Version Banners

Each version can display a banner at the top of every page to inform users about the version's status. Two banner types are available:

### Unmaintained

```ts
banner: "unmaintained",
```

Shows a warning-styled banner indicating the user is viewing documentation for an older version, with a link to the latest version.

### Unreleased

```ts
banner: "unreleased",
```

Shows an info-styled banner indicating the user is viewing documentation for an unreleased version, with a link to the latest stable version.

### No Banner

```ts
banner: false,
```

Disables the banner for that version. This is the default when `banner` is omitted.

[Dynamic content unavailable in text export]

Use `"unmaintained"` for archived versions that are no longer updated, and `"unreleased"` for documentation of upcoming features that haven't shipped yet.



## Multi-Locale Support

Each version can define its own locale directories, independent of the main locale configuration:

```ts
versions: [
  {
    slug: "1.0",
    label: "1.0.0",
    docsDir: "src/content/docs-v1",
    locales: {
      ja: { dir: "src/content/docs-v1-ja" },
      de: { dir: "src/content/docs-v1-de" },
    },
    banner: "unmaintained",
  },
],
```

For each version and locale combination, zudo-doc creates a separate content collection (e.g., `docs-v-1.0-ja`) and generates the corresponding page routes.

## Creating a New Version

When you're ready to archive the current documentation as a new version:

1. **Copy the current content directory** to a new versioned directory:

   ```bash
   cp -r src/content/docs src/content/docs-v2
   ```

2. **Copy each configured locale directory** if applicable:

   ```bash
   cp -r src/content/docs-ja src/content/docs-v2-ja
   cp -r src/content/docs-de src/content/docs-v2-de
   ```

3. **Add the version to settings**:

   ```ts
   versions: [
     {
       slug: "2.0",
       label: "2.0.0",
       docsDir: "src/content/docs-v2",
       locales: {
         ja: { dir: "src/content/docs-v2-ja" },
         de: { dir: "src/content/docs-v2-de" },
       },
       banner: "unmaintained",
     },
     // ...existing versions
   ],
   ```

4. **Update the current docs** — The files in `src/content/docs/` now represent the latest version. Update them as needed for the new release.

[Dynamic content unavailable in text export]

The `versions` array defines older or pre-release versions only. The current/latest version always uses the main `docsDir` and is not listed in the array.