Configuration

Configuration

All site configuration lives in a single chronicle.yaml file in your project root. The config is validated using Zod — invalid fields produce clear errors at startup.

Project layout

my-docs-site/
├── chronicle.yaml
├── content/                     ← latest
│   ├── docs/
│   └── dev/
└── versions/                    ← only if versions: is declared
    ├── v2/
    │   └── docs/
    └── v1/
        ├── docs/
        └── dev/

Content dirs declared in top-level content: are resolved under content/<dir>/ for the latest version; each versions[].content[].dir is resolved under versions/<version-dir>/<dir>/.

Full example

site:
  title: My Project Docs
  description: Documentation for My Project

url: https://docs.example.com
preset: vercel

logo:
  light: ./logo-light.png
  dark: ./logo-dark.png

theme:
  name: default

content:
  - dir: docs
    label: Docs
  - dir: dev
    label: Dev Docs

latest:
  label: "3.0"
  landing: true

versions:
  - dir: v2
    label: "2.0"
    content:
      - dir: docs
        label: Docs

  - dir: v1
    label: "1.0"
    landing: true
    badge:
      label: deprecated
      variant: warning
    content:
      - dir: dev
        label: Developer Guide
      - dir: docs
        label: Docs
    api:
      - name: REST API (v1)
        spec: ./v1-openapi.yaml
        basePath: /apis
        server:
          url: https://api.example.com/v1

navigation:
  links:
    - label: GitHub
      href: https://github.com/myorg/myproject

links:
  - label: Support
    href: https://support.example.com

search:
  enabled: true
  placeholder: Search docs...

api:
  - name: REST API
    spec: ./openapi.yaml
    basePath: /apis
    server:
      url: https://api.example.com
      description: Production Server
    auth:
      type: apiKey
      header: Authorization
      placeholder: "Bearer token"

redirects:
  - from: /old-page
    to: /docs/new-page
  - from: /legacy/api
    to: /apis
    permanent: true

analytics:
  enabled: true
  googleAnalytics:
    measurementId: G-XXXXXXXXXX

telemetry:
  enabled: true
  serviceName: my-docs
  port: 9090

Reference

site

Required. Site-level metadata.

site:
  title: My Documentation
  description: Documentation powered by Chronicle
FieldTypeDescription
titlestringSite title (navbar, browser tab, canonical metadata). Required.
descriptionstringMeta description for SEO and OG.

url

Optional site URL used for the sitemap and canonical URLs.

url: https://docs.example.com

content

Required. Content dirs for the latest version. Each entry maps to content/<dir>/ on disk and to /<dir>/... in URLs.

content:
  - dir: docs
    label: Docs
  - dir: dev
    label: Dev Docs
FieldTypeDescription
dirstringFolder name under content/. Must be unique.
labelstringDisplay label in navigation and landing pages.
descriptionstringOptional description shown on landing page cards.
iconstringOptional icon identifier for landing page cards.

latest

Optional metadata for the latest version. Required when versions: is declared.

latest:
  label: "3.0"
  landing: true
FieldTypeDescriptionDefault
labelstringVersion label (e.g. 3.0). Shown in the version switcher, or as a static label in the sidebar footer when no versions: are declared.
landingbooleantrue/ renders a landing page listing content dirs. false (default) → / 302s to the first content dir.false

versions

Optional list of older versions. Each entry lives under versions/<dir>/ on disk and is reachable at /<dir>/... in URLs.

versions:
  - dir: v1
    label: "1.0"
    landing: true
    badge:
      label: deprecated
      variant: warning
    content:
      - dir: dev
        label: Developer Guide
      - dir: docs
        label: Docs
    api:
      - name: REST API (v1)
        spec: ./v1-openapi.yaml
        basePath: /apis
        server:
          url: https://api.example.com/v1
FieldTypeDescription
dirstringFolder name under versions/. Doubles as URL prefix. Must be unique.
labelstringVersion label. Shown in the switcher.
landingbooleantrue/<dir> renders a landing page; otherwise 302s to the version's first content dir. Default false.
badgeobjectOptional Apsara badge next to the version label.
badge.labelstringBadge text.
badge.variant"accent" | "warning" | "danger" | "success" | "neutral" | "gradient"Badge colour. Default accent.
content{dir, label}[]Content dirs for this version. Entries may rename, reorder, or omit top-level content dirs.
apiApiConfig[]Version-scoped API specs, rendered at /<dir>/apis/.... Same shape as top-level api:.

preset

Optional deploy preset. Can be overridden by --preset.

preset: vercel # vercel, cloudflare, or node-server

Logo with theme-aware variants.

logo:
  light: ./logo-light.png
  dark: ./logo-dark.png
FieldTypeDescription
lightstringLogo path or URL for light theme
darkstringLogo path or URL for dark theme

theme

Theme selection and customization.

theme:
  name: default
FieldTypeDescriptionDefault
name'default' | 'paper' | 'fanfold'Theme to usedefault
colorsRecord<string, string>Custom color overrides

See Themes for details on each theme.

Top navbar links and social icons.

navigation:
  links:
    - label: GitHub
      href: https://github.com/myorg/myproject
  social:
    - type: github
      href: https://github.com/myorg/myproject

navigation.links

FieldTypeDescription
labelstringLink text
hrefstringURL (internal or external)

navigation.social

FieldTypeDescription
typestringIcon type: github, twitter, discord, or custom
hrefstringURL

Links shown in the sidebar footer, behind a ? menu button next to the version switcher. Available in the default, paper and fanfold themes.

links:
  - label: Go to app
    href: https://app.example.com
  - label: Support
    href: https://support.example.com
FieldTypeDescription
labelstringMenu item text
hrefstringURL. Absolute URLs open in a new tab; relative paths navigate in-app

External links are tagged with UTM query params so the destination can attribute the visit, using the standard names every analytics tool recognises:

ParamValue
utm_sourceHostname of the docs site the click came from
utm_mediumsite.title, slugified
utm_contentPath of the page the link was clicked from
https://support.example.com?utm_source=docs.example.com&utm_medium=my-documentation&utm_content=%2Fdocs%2Fguide

External links open with noopener (not noreferrer), so the destination also receives a Referer header — but under the browser default referrer policy that header carries only the origin, so utm_content is what identifies the specific page.

Any query string already on href is preserved, and a utm_* param you set yourself is never overwritten. Relative paths are not tagged — they stay on the same origin, so the params would only register as a self-referral. Non-web schemes (mailto:, slack:) are left untouched.

Search functionality powered by Fumadocs. Automatically scoped to the active version.

search:
  enabled: true
  placeholder: Search documentation...
FieldTypeDescriptionDefault
enabledbooleanEnable/disable searchtrue
placeholderstringSearch input placeholderSearch...

When enabled, search is accessible via the navbar button or keyboard shortcut Cmd+K / Ctrl+K. Active version comes from the URL; switching versions scopes the index.

api

OpenAPI specification configuration at the top level applies to the latest version (served at /apis/...). Version-scoped specs live under each versions[].api.

api:
  - name: Petstore API
    spec: ./petstore.yaml
    basePath: /apis
    server:
      url: https://petstore.swagger.io/v2
      description: Production Server
    auth:
      type: apiKey
      header: api_key
      placeholder: Enter your API key
FieldTypeDescription
namestringAPI display name
specstringPath to OpenAPI spec file (JSON or YAML), relative to chronicle.yaml
basePathstringURL path prefix for API pages (e.g., /apis)
iconstringOptional icon identifier
server.urlstringBase URL for the API server
server.descriptionstringServer description
auth.typestringAuthentication type (e.g., apiKey, bearer)
auth.headerstringHeader name for auth token
auth.placeholderstringPlaceholder text in auth input

redirects

URL redirects for migrating old routes to new ones. Checked before all other routes.

redirects:
  - from: /old-page
    to: /docs/getting-started
  - from: /legacy/api-docs
    to: /apis
    permanent: true
FieldTypeDescriptionDefault
fromstringOld URL path to redirect from
tostringNew URL path to redirect to
permanentbooleantrue for 308 (permanent), false for 307 (temporary)false

Use permanent: true when the old URL should never be used again — search engines and browsers will cache the redirect.

analytics

Analytics integration for tracking page views.

analytics:
  enabled: true
  googleAnalytics:
    measurementId: G-XXXXXXXXXX
FieldTypeDescriptionDefault
enabledbooleanEnable/disable analyticsfalse
googleAnalytics.measurementIdstringGoogle Analytics measurement ID

authors

Optional registry of the people who write your docs. Pages reference an entry by its key in their authors frontmatter, so the details live in one place.

authors:
  jane:
    name: Jane Doe
    bio: Writes about distributed systems.
    avatar: /team/jane.png
    url: https://github.com/jane
    email: jane@example.com
FieldTypeDescriptionDefault
namestringRequired. Display name
biostringShort description shown on the author's page
avatarstringImage path for the avatar; initials are used without it
urlstringProfile link, shown on the author's page
emailstringContact address, shown on the author's page with mailto:
# page.mdx frontmatter
authors: [jane]

A frontmatter string that matches no key is still valid — it renders as a plain name, so occasional contributors need no registry entry. See Frontmatter for the field itself, and browse the people writing a site at /authors.

telemetry

Prometheus metrics export via OpenTelemetry. Served on a separate port.

telemetry:
  enabled: true
  serviceName: my-docs
  port: 9090
FieldTypeDescriptionDefault
enabledbooleanEnable/disable telemetryfalse
serviceNamestringOpenTelemetry service namechronicle
portnumberPort for Prometheus metrics endpoint9090

Metrics are available at http://localhost:<port>/metrics in Prometheus exposition format.

Defaults

When chronicle.yaml is missing or fields are omitted, these defaults apply:

site:
  title: Documentation
content:
  - dir: docs
    label: Docs
theme:
  name: default
search:
  enabled: true
  placeholder: Search...