Last updated June 23, 2026

Configuration

3 minutes read

All site-level settings live in folio.config.ts at the repository root. Export a configuration built with defineFolioConfig:

tsfolio.config.ts
import { defineFolioConfig } from "folio-md/types";
 
export default defineFolioConfig({
  name: "My Docs",
  description: "Documentation for my project.",
});

defineFolioConfig validates the configuration at startup and throws a descriptive error if something is wrong.

Fields

Core

FieldTypeDefaultDescription
namestringrequiredSite name displayed in the navbar and <title>
descriptionstringrequiredFallback meta description for pages without their own
contentDirstring"./docs"Path to the MDX content directory, relative to the repository root
langstring"en"Value of the <html lang> attribute
siteUrlstringrequiredCanonical base URL for your site, used for canonical links and Open Graph URLs. Must start with https:// or http://.

Light theme

ts
light: {
  enabled: true,            // default; set false to turn off light mode entirely
  gradient: {
    from: "#c7d2fe",        // top-left corner color
    to:   "#ddd6fe",        // bottom-right corner color
  },
  icons: {
    favicon:       "/icon-light.svg",  // path under public/
    appleTouchIcon: "/apple-touch-icon.png",
  },
}

Dark theme

ts
dark: {
  enabled: false,           // default; set true to enable dark mode
  gradient: {
    from: "#020617",
    to:   "#1e1b4b",
  },
  icons: {
    favicon: "/icon-dark.svg",
  },
}

When both light.enabled and dark.enabled are true, a toggle button appears in the navbar and folio.md persists the user’s preference in localStorage.

Search engine optimization

ts
seo: {
  locale:        "en_US",       // used in og:locale; underscores are normalized automatically
  robots:        "index, follow",
  twitterHandle: "myhandle",    // without the @
}

Analytics

ts
gaId: "G-XXXXXXXXXX",   // Google Analytics measurement ID

When you set gaId, folio.md renders a cookie consent banner on every page. Analytics events fire only after the user accepts.

Accent color

ts
accentHue: 220,   // OKLCH hue, 0-360; default 264 (indigo)

folio.md derives all accent colors in the UI from a single hue value. This covers active nav links, blockquotes, inline code, and checkboxes. Change this one number to shift the entire palette without touching CSS.

The default hue is 264, which produces indigo. Some useful alternatives:

HueColor
264Indigo
220Blue
160Teal
145Green
25Orange
340Pink
ts
editLink: {
  base: "https://github.com/your-org/your-repo/edit/main/docs",
},

When set, a pencil icon link appears inline next to the page title on every content page. The full URL is base + "/" + originalFilePath, where originalFilePath preserves numeric ordering prefixes, such as guide/01.Getting Started.mdx. The link isn’t shown on pages that set showTitle: false.

Pagination

ts
pagination: true,   // default; set false to hide prev/next cards on all pages

Previous / next navigation cards appear below each page’s content. They follow the sidebar order. Set to false to remove them site-wide.

ts
footer: {
  text:  "© 2025 My Company",
  links: [
    { label: "Privacy", href: "/privacy" },
    { label: "GitHub",  href: "https://github.com/your-org" },
  ],
},

Renders a minimal footer bar below the content area. Both text and links are optional. Omit the footer key entirely to show no footer.

Prose linting

ts
vale: {
  configFile:    "./.vale.ini",        // optional: path to your own .vale.ini; disables all auto-generated config
  minErrorLevel: "warning",            // "suggestion" | "warning" | "error" (default: "error"; ignored when configFile is set)
  accept:        ["myword", "MyTerm"], // words to add to Vale's accept list (ignored when configFile is set)
},

Run folio:lint to lint your documentation with Vale.

Two style sets are active by default:

  • Vale: Vale’s built-in rules covering grammar, spelling, and more
  • Google: Google’s developer documentation style guide

folio.md downloads both packages automatically on first run and caches them at ~/.folio-md/vale-styles/, no setup required.

All issues at every level are always displayed. minErrorLevel controls only the exit code: folio lint returns a non-zero exit code if folio lint finds any issues that reach or exceed that level, making it suitable for CI. The default is "error", so suggestions and warnings are visible but don’t fail the build.

Use accept to allowlist words that Vale would otherwise flag: project-specific terms, proper nouns, or technical jargon. Vale writes each string as a line in its vocabulary accept file and treats each line as a regular expression. Plain words work as-is. Patterns let you match multiple forms at once:

ts
accept: [
  "MyCompany",       // exact match
  "[Mm]ylib",        // matches "Mylib" and "mylib"
  "(?i)api",         // case-insensitive match for any capitalization of "api"
],

If you need full control over Vale, set configFile to point at your own .vale.ini. folio.md skips all configuration generation and passes your file directly to Vale. folio.md ignores minErrorLevel and accept when you set configFile.

Vale isn’t installed automatically. Install it first:

bash
brew install vale          # macOS / Linux (Homebrew)
snap install vale          # Linux (Snap)
choco install vale         # Windows
ts
navbar: {
  links: [
    { label: "GitHub", href: "https://github.com/your-org", icon: "GitBranch" },
    { label: "Star",   href: "https://github.com/your-org/star",  icon: "Star" },
  ],
},

Extra icon buttons rendered in the navbar between the search bar and the theme toggle. The icon field accepts any name from the Icons reference. External links that start with http open in a new tab automatically. Omit icon to render the label as plain text.

Full example

tsfolio.config.ts
import { defineFolioConfig } from "folio-md/types";
 
export default defineFolioConfig({
  name: "My Docs",
  description: "Documentation for my project.",
  contentDir: "./docs",
  lang: "en",
  siteUrl: "https://docs.example.com",
  light: {
    enabled: true,
    gradient: { from: "#e0f2fe", to: "#f0fdf4" },
    icons: { favicon: "/favicon.svg", appleTouchIcon: "/apple-touch.png" },
  },
  dark: {
    enabled: true,
    gradient: { from: "#0f172a", to: "#1e1b4b" },
    icons: { favicon: "/favicon-dark.svg" },
  },
  seo: {
    locale: "en_US",
    robots: "index, follow",
    twitterHandle: "alicehandle",
  },
  gaId: "G-XXXXXXXXXX",
  accentHue: 220,
  editLink: {
    base: "https://github.com/your-org/your-repo/edit/main/docs",
  },
  pagination: true,
  footer: {
    text: "© 2025 My Company",
    links: [
      { label: "Privacy", href: "/privacy" },
      { label: "GitHub",  href: "https://github.com/your-org" },
    ],
  },
  navbar: {
    links: [
      { label: "GitHub", href: "https://github.com/your-org", icon: "GitBranch" },
    ],
  },
  vale: {
    // configFile: "./.vale.ini",  // uncomment to use your own Vale config entirely
    minErrorLevel: "error",
    accept: ["MyCompany", "mylib"],
  },
});