A documentation site generator for developers who want a fast, readable site without pulling in a framework.
pnpm add @erikt/docgen- No build step — runs TypeScript directly via Node.js
>=23.6. Notsc, noesbuild, no config files to maintain. - File-based routing — drop a
.mdor.tsfile inpages/and it becomes a route. Directories become sidebar sections automatically. - Static output —
docgen buildwrites plain HTML files. Deploys to GitHub Pages or any static host with no special setup. - Syntax highlighting — code blocks highlighted at build time via Shiki. Accurate language grammars, zero client-side JS.
- Full-text search — built-in search across all pages powered by MiniSearch. No server, no indexing pipeline.
- Light & dark mode — follows the system preference out of the box, with a toggle that persists across visits.
- Table of contents — headings on each page are linked in a right-hand column, with scroll-position tracking.
- Lean on the platform —
node:httpfor the server,node:fsfor file watching, modern CSS for theming. Short dependency list by design.
Create docs.config.ts in your project root:
import { defineDocs } from "@erikt/docgen";
export default await defineDocs({
structure: [{ label: "Guide", path: "/guide", icon: "book" }],
});Add scripts to package.json:
{
"scripts": {
"dev": "docgen dev",
"build": "docgen build"
}
}Then run:
pnpm dev
# listening on http://localhost:5151Files in pages/ map directly to routes:
| File | Route |
|---|---|
pages/index.md |
/ |
pages/guide/installation.md |
/guide/installation |
Both .md and .ts files are supported. Markdown is processed through remark/rehype with GitHub Flavored Markdown and Shiki syntax highlighting. TypeScript pages export a SafeHtml value built with the html tagged template.
Prefix filenames with a number to control sidebar order — the prefix is stripped from the URL and display name.
docgen build writes a static site to dist/. See the deployment guide for a ready-to-use GitHub Actions workflow.
If your site is served from a sub-path (e.g. GitHub Pages), set the base option:
export default await defineDocs({
base: "/my-repo",
});