Multiple Docs Sections

A single docs() call can produce several independent documentation sections — for example /docs for user guides and /api-docs for API reference. Each section gets its own URL, sidebar navigation, and vault folder.

Why use multiple sections

A single docs section works well for small sites. As content grows, you may want to separate concerns:

  • /docs — end-user guides, tutorials, how-to articles
  • /api-docs — API reference pulled from a different vault folder
  • /reference — configuration reference or CLI docs

Each section is independent: it has its own Astro content collection, its own sidebar, and its own menu entry. Disabling one section does not affect the others.

Basic setup

Pass an array to docs() instead of a single object:

// karaoke.config.ts
import { docs } from '@karaoke-cms/module-docs';

modules: [
  docs([
    { mount: '/docs',     label: 'Docs',          weight: 20 },
    { mount: '/api-docs', folder: 'api-reference', label: 'API Reference', weight: 21 },
  ]),
]

Each entry in the array has the same options as the single-instance form. The array is flattened automatically by karaoke().

Section options

FieldTypeDefaultDescription
mountstringrequiredURL mount point (e.g. '/docs')
folderstringmount without leading /Vault subfolder to read content from
idstringfolder name with /-Unique identifier; also the Astro collection name
labelstringtitle-cased idDisplay label in nav and page titles
weightnumber20Menu sort order. Lower = earlier. Blog = 10, Tags = 30
enabledbooleantrueWhen false, section is excluded from the build
commentsbooleanfalseWhen true, comments are on by default for all pages in the section
sidebarStylestring'tree'Sidebar style override ('flat' or 'grouped')
layoutstring'default'Layout component override
parentstringId of a root menu entry to nest this entry under

Vault folders

Each section reads from a subfolder of your vault. The folder defaults to the mount path with the leading / stripped:

mount: '/docs'      → folder: 'docs'
mount: '/api-docs'  → folder: 'api-docs'

Override it with folder when the vault folder name differs from the mount path:

{ mount: '/api-docs', folder: 'api-reference' }
// reads from {vault}/api-reference/
// serves at /api-docs/

Create the folder in your vault and add Markdown files. Files without publish: true in frontmatter are excluded from production builds.

Section IDs and collections

Each section creates one Astro content collection. The collection name is the section id.

The id defaults to the folder name with slashes replaced by hyphens:

folder: 'api-reference'  →  id: 'api-reference'
folder: 'docs'           →  id: 'docs'

IDs must be unique. If two sections share the same id, karaoke() throws an error at startup. Set id explicitly when the default would collide:

docs([
  { mount: '/docs',    id: 'user-docs',  label: 'Docs' },
  { mount: '/docs/v2', id: 'docs-v2',    label: 'Docs v2' },
])

Wiring up content.config.ts

makeCollections must receive the full config so it can register one collection per docs instance. The scaffolder emits this by default:

// src/content.config.ts
import { makeCollections } from '@karaoke-cms/astro';
import { loadEnv } from '@karaoke-cms/astro/env';
import config from '../karaoke.config';

const env = loadEnv(new URL('..', import.meta.url));
export const collections = makeCollections(
  new URL('..', import.meta.url),
  env.KARAOKE_VAULT,
  { config },           // ← passes modules[] so each docs section gets its collection
);

If { config } is omitted, docs sections beyond the first will not have their collections registered and their pages will return 404.

Each section automatically registers a menu entry in the main nav. The weight field controls the order.

To nest a section under another entry, use parent:

docs([
  { mount: '/docs',     id: 'docs',    label: 'Docs',          weight: 20 },
  { mount: '/api-docs', id: 'api-docs', label: 'API Reference', weight: 25, parent: 'docs' },
])

parent references a root-level menu entry by id. Nesting is single-level only. If the referenced id is not found at build time, a warning is logged and the entry falls back to root level.

You can also control menu layout directly in menus.yaml:

# {vault}/_website/menus.yaml
main:
  entries:
    - id: docs
      text: Docs
      href: /docs
    - text: API Reference
      href: /api-docs
      parent: docs

Disabling a section

Set enabled: false to remove a section from the build without deleting it from config:

docs([
  { mount: '/docs',     label: 'Docs',          weight: 20 },
  { mount: '/api-docs', label: 'API Reference',  weight: 21, enabled: false },
])

Disabled sections are excluded from the returned ModuleInstance[]. Their routes, collections, and menu entries are all suppressed.

Full example

// karaoke.config.ts
import { defineConfig } from '@karaoke-cms/astro';
import { loadEnv } from '@karaoke-cms/astro/env';
import { docs } from '@karaoke-cms/module-docs';
import { themeDefault } from '@karaoke-cms/theme-default';

const env = loadEnv(new URL('.', import.meta.url));

export default defineConfig({
  vault: env.KARAOKE_VAULT,
  theme: themeDefault(),
  modules: [
    docs([
      {
        mount: '/docs',
        label: 'User Guide',
        weight: 20,
      },
      {
        mount: '/api-docs',
        folder: 'api-reference',
        label: 'API Reference',
        weight: 21,
        comments: true,
      },
    ]),
  ],
});

Corresponding vault layout:

karaoke-website-vault/
  docs/             ← content for /docs
    getting-started.md
    installation.md
  api-reference/    ← content for /api-docs
    overview.md
    endpoints.md