Skip to content
flypod
Guides

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 ./docs

The 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 README or index file 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>.html next 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           # → /api

deploys 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/install
HTTP/1.1 200 OK
Content-Type: text/markdown; charset=utf-8
Vary: Accept
X-Markdown-Tokens: 214
  • The Accept header decides. Accept: text/markdown (ranked at or above text/html) returns Markdown; a browser's HTML-preferring Accept always 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 Accept preference (no header, or a bare */*) — cleaner input for them, unchanged pages for everyone else.
  • X-Markdown-Tokens gives an agent a rough token estimate up front so it can budget its context window before reading the body.
  • Vary: Accept is 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.

Next steps

On this page