Auto-Generate VitePress Sidebar from File Structure
Filesystem-driven sidebar with glob — stop hand-editing config when adding pages.
Tested on: VitePress 1.6.3, Node 20, 12 sections / 340 files
Problem: Every new page required editing config.mts.
Install glob helper
npm i -D fast-glob
Generator module
.vitepress/utils/sidebar.mjs:
import fg from 'fast-glob'
import path from 'node:path'
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const DOCS = path.resolve(__dirname, '../../docs')
function titleFromFile(file) {
const raw = fs.readFileSync(path.join(DOCS, file), 'utf8')
const m = raw.match(/^title:\s*(.+)$/m)
if (m) return m[1].trim().replace(/["']/g, '')
return path.basename(file, '.md').replace(/-/g, ' ')
}
export function sidebarFor(prefix) {
const files = fg.sync(`${prefix}/**/*.md`, {
cwd: DOCS,
ignore: ['**/index.md']
}).sort()
return files.map(f => ({
text: titleFromFile(f),
link: '/' + f.replace(/\.md$/, '')
}))
}
Wire into config
.vitepress/config.mts:
import { sidebarFor } from './utils/sidebar.mjs'
export default defineConfig({
themeConfig: {
sidebar: {
'/guide/': sidebarFor('guide'),
'/api/': sidebarFor('api')
}
}
})
Nested groups
export function nestedSidebar(prefix) {
const files = fg.sync(`${prefix}/**/*.md`, { cwd: DOCS })
const groups = new Map()
for (const f of files) {
const parts = f.split('/')
if (parts.length <= 2) continue
const group = parts[1]
if (!groups.has(group)) {
groups.set(group, { text: group.replace(/-/g, ' '), collapsed: false, items: [] })
}
groups.get(group).items.push({
text: titleFromFile(f),
link: '/' + f.replace(/\.md$/, '')
})
}
return [...groups.values()]
}
Errors
Sidebar link 404
Enable cleanUrls: true in config.
Cannot find module sidebar.mjs
Use .mjs + fileURLToPath for __dirname.
Verify
node -e "import('./.vitepress/utils/sidebar.mjs').then(m => console.log(m.sidebarFor('guide').length))"
npm run docs:dev
# add new .md → sidebar updates automatically
Result
Zero manual sidebar PRs. Config load +200ms — negligible.