Configuration
Methanol reads configuration from:
methanol.config.{js,mjs,cjs,ts,jsx,tsx,mts,cts}
If no config is present, Methanol uses defaults based on the current directory.
Config Shape
The config file must export a function. The function receives a context object and returns a config object.
export default ({ mode, root, HTMLRenderer }) => ({
// config values
})
Context fields:
mode:developmentorproductionroot: project rootHTMLRenderer: refui HTML utilities (rawHTML,serialize, etc.)
Core Options
root
Project root. Defaults to the current working directory.
site
Site metadata used by templates:
site.name: site titlesite.logo: logo path (string) orfalseto disable (default theme)site.favicon: favicon path (string) orfalseto disable (default theme)site.base: deployment base (path prefix) when the site is served under a subpath (e.g.'/docs/')site.repoBase: base URL to your content folder in a repo (used by the default theme to build “Edit this page” links)
Notes:
site.baseis normalized to a leading and trailing slash (e.g.docs→'/docs/').site.baseis used as the default Vitebaseunless you explicitly setvite.base.- In dev (
methanol dev),site.baseis ignored and treated as/due to Vite module resolution inconsistencies. Verify subpath deployments withmethanol build+methanol serve.
pagefind
Enable or configure Pagefind search. Default: false.
pagefind: false
// or
pagefind: { enabled: true }
// or
pagefind: {
enabled: true,
excerptLength: 30,
build: {
outputSubdir: 'pagefind',
verbose: true
}
}
Notes:
- Keys other than
enabledandbuildare forwarded to the Pagefind JSoptions()call. buildis the only build options entry.
starryNight
Controls code highlighting (rehype-starry-night). Default: false.
starryNight: false
// or
starryNight: true
// or
starryNight: {
// options forwarded to rehype-starry-night
}
- If
starryNightis an object, highlighting is enabled unlessenabled: falseis set. - Per-page frontmatter
starryNightalways overrides this value. - CLI
--code-highlightingcan enable or disable highlighting for a run.
gfm
Enable or disable GitHub Flavored Markdown (GFM). Default: true.
When enabled, Methanol applies GFM parsing (tables, task lists, strikethrough, footnotes, autolink literals).
gfm: true
// or
gfm: false
pagesDir
Where MDX/MD files live (routes). Default: pages with a fallback to docs if pages/ does not exist.
componentsDir
Where JSX/TSX components live. Default: components.
If you explicitly set pagesDir or componentsDir (including via CLI), Methanol throws if the directory does not exist.
publicDir
Static assets folder served at the site root (e.g. public/foo.png → /foo.png). Default: public.
Methanol also includes theme public assets (theme.publicDir). When both theme and user assets exist, Methanol merges them into a single directory (theme first, then user), so user assets override theme assets on path conflicts.
When merging is needed, the internal merged directory is created under node_modules/.methanol/assets (or {pagesDir}/.methanol/assets if node_modules/ does not exist).
Set publicDir: false to disable public assets entirely (including theme assets).
distDir
Output folder for production builds. Default: dist.
buildDir
Intermediate build directory (used with emitIntermediate). Default: build.
intermediateDir
Explicit directory to write intermediate HTML output (build only).
emitIntermediate
Boolean. When true, Methanol writes intermediate HTML to build/ during build.
theme
Theme configuration. See Advanced themes for full usage.
Key fields:
theme.root: theme root directory (required)theme.template: HTML template function (receives{ ctx, page, PageContent, ExtraHead, withBase, HTMLRenderer, components })theme.components: default MDX componentstheme.componentsDir: folder of theme componentstheme.pagesDir: folder of theme pagestheme.publicDir: theme public assets (merged intopublicDir)theme.sources: virtual file map used by Methanol’s resolvertheme.mdx: default MDX options merged with usermdxtheme.vite: default Vite config merged with uservite
mdx
Customize MDX compilation. This function receives { mode, root } and should return MDX options.
vite
Merge custom Vite config. This function receives { command, mode, root, isPreview }.
preBuild / preBundle / postBundle / postBuild
Hooks for customizing the build pipeline.
preBuildruns in dev startup and before build.preBundleruns only during build, after pages are rendered and before Vite bundles assets.postBundleruns only during build, after Vite bundles assets and before Pagefind indexing.postBuildruns only after build (not in dev).- Hooks can be a function or an array of functions.
- Hook order: user
preBuild→ themepreBuild→ render → userpreBundle→ themepreBundle→ bundle → themepostBundle→ userpostBundle→ (optional) Pagefind → themepostBuild→ userpostBuild.
Hook context:
mode,root,command,isDev,isBuild,isPreviewHTMLRenderersite(same shape asctx.site)data(mutable object for sharing data between hooks)
Bundle/post-build hooks also receive:
pagesContextpagespagesTreepagesByRoute
Example:
export default () => ({
preBuild: ({ data, site }) => {
data.startedAt = Date.now()
console.log('Building', site.name)
},
preBundle: ({ pages }) => {
console.log('Rendered pages:', pages.length)
},
postBuild: ({ data, pages }) => {
console.log('Duration (ms):', Date.now() - data.startedAt)
console.log('Pages:', pages.length)
}
})
CLI Overrides
Command line options override config values:
--inputand--componentsoverridepagesDirandcomponentsDir--assetsoverridespublicDir--outputoverridesdistDir--site-nameoverridessite.name--baseoverridessite.basefor a run (ignored in dev)-v/--verboseenables verbose output for the run--configselects a specific config file- Positional
input/outputmatch--input/--output(dev uses onlyinput)
Example
import tailwindcss from '@tailwindcss/vite'
export default ({ mode }) => ({
site: { name: 'My Docs' },
theme: {
root: '.',
template: ({ PageContent, ExtraHead, ctx, withBase, HTMLRenderer, components }) => (
<>
{HTMLRenderer.rawHTML`<!doctype html>`}
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<ExtraHead />
<title>{ctx.page.title || ctx.site.name}</title>
<link rel="icon" href="/favicon.png" />
</head>
<body>
{components.Callout ? <components.Callout>Hi</components.Callout> : null}
<PageContent />
</body>
</html>
</>
),
components: {
Callout: ({ children }) => <div class="callout">{children}</div>
}
},
mdx: () => ({
development: mode !== 'production'
}),
vite: () => ({
server: { port: 5173 },
plugins: [tailwindcss()]
})
})