Render Markdown to a docs site
Deploy a folder of Markdown files with no index.html and flypod renders them into a styled docs site with a sidebar and home page.
Deploy a folder of Markdown and flypod turns it into a styled HTML docs site:
npx flypod ./docsThe rule
flypod renders Markdown only when the deployed folder has no root
index.html. It picks up .md, .markdown, and .mdx files and converts
them to HTML using GFM (GitHub Flavored Markdown, via marked).
If the folder already has a root index.html, flypod serves it as-is,
untouched. No rendering happens. The Markdown-to-docs behavior is a fallback
for folders that have no HTML entry point.
What you get
- Multiple docs → a navigation sidebar linking every page.
- A
READMEorindexfile becomes the home page. With no such file, a lone doc becomes the home page, and several docs get a generated "Documentation" page listing them. - Each page's title is its first
# H1; if there is none, flypod prettifies the filename. - Each doc becomes
<name>.htmlnext to its source (guide/setup.md→/guide/setup.html), reachable without the extension too (/guide/setup). - A light/dark theme toggle, remembered per browser.
- The raw Markdown is still served at its own path as
text/markdown, so the source stays fetchable.
Rendered pages run no script from your Markdown: <script> tags, on…
attributes and javascript: links in the source are stripped from the HTML.
Ship your own index.html if a page needs JavaScript.
Example
A folder like this:
docs/
README.md # → home page
install.md # → /install
api.md # → /apideploys to a docs site whose home is README.md, with install and api in
the sidebar. A page that starts with # Installing flypod gets the title
"Installing flypod"; a file named getting-started.md with no H1 gets
"Getting Started".
Agents get Markdown, browsers get HTML
Every rendered page is available in two representations at the same URL: the styled HTML a browser sees, and the raw Markdown source an AI agent would rather read. flypod picks between them per request using standard HTTP content negotiation — no separate URL, no config.
An agent that sends Accept: text/markdown gets the Markdown back:
curl -H "Accept: text/markdown" https://<your-site>.flypod.page/installHTTP/1.1 200 OK
Content-Type: text/markdown; charset=utf-8
Vary: Accept
X-Markdown-Tokens: 214- The
Acceptheader decides.Accept: text/markdown(ranked at or abovetext/html) returns Markdown; a browser's HTML-preferringAcceptalways returns HTML. This is the same 27-year-old mechanism every HTTP client already speaks, and the convention coding agents like Claude Code use. - Known AI agents and crawlers (GPTBot, ClaudeBot, PerplexityBot, Claude
Code, and friends) get Markdown when they send no
Acceptpreference (no header, or a bare*/*) — cleaner input for them, unchanged pages for everyone else. X-Markdown-Tokensgives an agent a rough token estimate up front so it can budget its context window before reading the body.Vary: Acceptis set on every response, so caches never hand a browser the Markdown or an agent the HTML.
The home page (/) negotiates too, returning the source of your README/
index doc (a generated "Documentation" list has no Markdown source, so it is
always HTML). This only applies to folders flypod rendered from Markdown — if you
ship your own index.html, your HTML is always served as-is, never replaced.
You can still fetch any source file directly at its .md path at any time.
Every site, rendered or not, also answers /llms.txt with a generated index of
its pages, unless the deploy ships its own llms.txt.
When to add an index.html instead
If you want full control over layout (your own HTML, CSS, and routing), ship an
index.html and flypod serves your folder verbatim. See
Deploy a site.