A zero-install styled previewer for .md / .mdx / .markdown files. Runs on localhost, live-reloads on save. One file, no npm dependencies. Doubles as a Claude Code skill.
Built for prepping docs you're about to share, reviewing PRDs, or just reading long markdown in a real browser instead of a code editor.
The fastest way, no install:
npx serve-doc path/to/file.md
# or: pnpm dlx serve-doc path/to/file.md
# or: bunx serve-doc path/to/file.mdAdd --open and it'll launch the browser for you:
npx serve-doc path/to/file.md --openIf you write engineering docs in markdown (PRDs, RFCs, design docs), most previewers were built for a different job:
- VS Code's built-in preview lives in the editor pane and uses wiki styling.
griprenders through the GitHub API: opinionated, rate-limited, online-only.glowis terminal-only.- Generic marked CLIs dump raw HTML with no TOC and no live-reload.
serve-doc is built for the doc-review use case: real browser, real typography, instant reload on save, theme-matched mermaid, plus light post-processing that turns bold-led paragraphs into callouts and B1. / S2. list prefixes into phase badges. One ~550-line file, zero npm dependencies (the browser pulls marked and mermaid from esm.sh).
- TOC sidebar auto-built from
h2/h3headings, with scroll-spy. - Mermaid diagrams that match light/dark theme.
- Coloured callouts: bold-led paragraphs starting with
Note.,Warning.,Recommendation., etc. get promoted to styled boxes. - Status pills: bare
DROPPED,NEW,KEEP,UNCHANGED,RECOMMENDEDget wrapped in pills. - Phase badges:
B1./S2./P3./V4./D1./C5.list prefixes become compact badges. - YAML frontmatter is stripped from the rendered output; a
title:key becomes the page title. - Local images (
) resolve relative to the doc's directory. - Dark mode that respects system preference and persists across reloads.
- Live reload via SSE +
fs.watch. Save in your editor, the browser refreshes. - Keyboard shortcuts:
/to jump to a section,tto toggle TOC,dto toggle dark mode.
npx serve-doc <file.md>npm i -g serve-doc
serve-doc <file.md>git clone https://github.com/csellis/serve-doc ~/.claude/skills/serve-docClaude Code auto-discovers it on next launch. Then ask Claude to "preview this markdown file" or "open foo.md in the browser."
git clone https://github.com/csellis/serve-doc
cd serve-doc
node serve-doc.mjs <file.md>| Flag | Default | Notes |
|---|---|---|
--port N |
8642 |
First free port from N..N+20 is used if N is taken. |
PORT=N (env) |
8642 |
Same as --port. |
--open, -o |
off | Open the served URL in your default browser on startup. |
The server binds to 127.0.0.1 only.
The bundled demo exercises every visual treatment:
npx serve-doc node_modules/serve-doc/examples/demo.md --open
# from a clone: pnpm demo:openlsof -i :8642 -sTCP:LISTEN # find the pid
kill <pid>Or just Ctrl-C if it's running in the foreground.
- Node 18+ (uses
fs.watch, ESM, top-levelawait). - A browser that can reach
esm.sh(the renderer is pulled at page load). Bun works as an alternative runtime:bun serve-doc.mjs file.md.
See CONTRIBUTING.md. Open an issue first for anything bigger than a one-line fix. Code of conduct: CODE_OF_CONDUCT.md. Security: SECURITY.md.
MIT. See LICENSE.