wikify.md
v1.0.1
Published
Runtime markdown docs viewer with Mermaid support for Fastify and framework-agnostic runtimes
Readme
wikify.md
wikify.md turns a folder of Markdown docs into a polished docs site with:
- automatic sidebar from your file tree
- full-text search
- syntax highlighting
- Mermaid diagram rendering (including
.mmdfiles) - light/dark mode and simple theme customization
It ships with:
- a framework-agnostic fetch handler (
wikify.md) - a Fastify plugin (
wikify.md/fastify)
Features
- Serves a docs SPA under a configurable route prefix (default:
/wiki) - Builds a nested sidebar from folders and
.md/.mmdfiles - Prioritizes
README.mdin each folder for better landing pages - Supports in-app search (
Cmd/Ctrl + K) across Markdown content - Renders Mermaid diagrams inline with an expandable pan/zoom viewer
- Theme controls: default dark mode, accent color, and code highlight theme
Install
npm install wikify.mdOr with Bun:
bun add wikify.mdQuick Start
Framework-Agnostic (Default)
import { createServer } from "node:http"
import wikify from "wikify.md"
const wiki = wikify({
docsDir: "./docs",
prefix: "/wiki",
title: "Project Docs",
})
createServer(async (req, res) => {
const origin = `http://${req.headers.host ?? "localhost"}`
const request = new Request(new URL(req.url ?? "/", origin), {
method: req.method,
headers: req.headers as HeadersInit,
})
const response = await wiki(request)
if (!response) {
res.statusCode = 404
res.end("Not found")
return
}
res.statusCode = response.status
response.headers.forEach((value, key) => res.setHeader(key, value))
res.end(Buffer.from(await response.arrayBuffer()))
}).listen(3000)Open http://localhost:3000/wiki.
Express.js
import express from "express"
import wikify from "wikify.md"
const app = express()
const wiki = wikify({
docsDir: "./docs",
prefix: "/wiki",
title: "Project Docs",
})
app.use(async (req, res, next) => {
const request = new Request(`${req.protocol}://${req.get("host")}${req.originalUrl}`, {
method: req.method,
headers: req.headers as HeadersInit,
})
const response = await wiki(request)
if (!response) return next()
res.status(response.status)
response.headers.forEach((value, key) => res.setHeader(key, value))
res.send(Buffer.from(await response.arrayBuffer()))
})
app.listen(3000)Open http://localhost:3000/wiki.
Fastify
import Fastify from "fastify"
import path from "node:path"
import wikify from "wikify.md/fastify"
const app = Fastify()
await app.register(wikify, {
docsDir: path.resolve("./docs"),
prefix: "/wiki",
title: "Project Docs",
})
await app.listen({ port: 3000 })Open http://localhost:3000/wiki.
Expected Docs Folder
docs/
README.md
getting-started.md
architecture/
README.md
request-flow.mmdNotes:
- Hidden files/folders (starting with
.) are ignored. - Only
.mdand.mmdfiles are listed in the sidebar. .mmdfiles are rendered as Mermaid diagrams automatically.
Configuration
The same config shape is used by both wikify(config) and app.register(wikify, config):
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| docsDir | string | required | Absolute or relative path to your docs directory |
| prefix | string | /wiki | Route prefix where docs UI and APIs are mounted |
| exclude | string[] | [] | Folder names to hide from tree/search |
| title | string | Docs | Navbar title |
| theme | WikifyTheme | { darkMode: true } | Theme options |
theme options
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| darkMode | boolean | true | Initial color mode |
| primaryColor | string | - | Accent color in hex (#rrggbb) |
| codeTheme | HljsTheme | github-dark | Syntax highlight theme |
Supported codeTheme values:
github-darkgithubatom-one-darkatom-one-lightnordnight-owltokyo-night-darkmonokai
Example With Theming
import path from "node:path"
import Fastify from "fastify"
import wikify from "wikify.md/fastify"
const app = Fastify()
await app.register(wikify, {
docsDir: path.resolve("./docs"),
prefix: "/docs",
title: "Acme Docs",
exclude: ["drafts", "private"],
theme: {
darkMode: true,
primaryColor: "#7c3aed",
codeTheme: "night-owl",
},
})Type-Safe Config Helper
If you keep config in a separate file, you can use defineConfig:
import { defineConfig } from "wikify.md"
export default defineConfig({
docsDir: "./docs",
prefix: "/wiki",
title: "My Docs",
})Routes Exposed
For a given prefix (for example /wiki), both variants expose:
GET /wikiandGET /wiki/*- docs UI shellGET /wiki/assets/*- static built UI assetsGET /wiki/_api/tree- sidebar file tree dataGET /wiki/_api/file?path=...- raw file contentGET /wiki/_api/search?q=...- search results (up to 20)
Mermaid Support
You can use Mermaid either inside Markdown fences:
```mermaid
flowchart LR
A[Client] --> B[Fastify]
B --> C[Docs]
```Or as standalone .mmd files in your docs folder.
Development
bun install
bun run dev
bun run buildBuild outputs:
- UI bundle:
dist/ui - Framework-agnostic bundle + types:
dist/plugin/index.* - Fastify plugin bundle + types:
dist/plugin/fastify.*
Compatibility
- Fastify:
>=4 - Framework-agnostic runtime: standard Web
Request/Response - Package runtime is ESM-first with CJS export support
If your docs include Mermaid content from untrusted sources, review your content pipeline carefully before serving it.
