Documentation

Last updated: 2026-09-27

Routing and content negotiation

How a Markdown-mode site turns a request path into content, and how the same page can answer with either HTML or its Markdown source.

Special endpoints

These are answered before any file lookup:

URLResponse
/sitemap.xmlXML sitemap of all pages
/index.xmlRSS 2.0 feed
/search-index.jsonSearch index as JSON
/searchSearch page
/tags/, /tags/<name>All tags, and the pages carrying one
/<taxonomy>/, /<taxonomy>/<value>The same for a custom taxonomy

Resolving a page

For any other path:

GET /<slug>

1. <slug>.md exists?          → render as Markdown
2. <slug>/index.md exists?    → render as Markdown
3. <slug>/index.html exists?  → serve as-is
4. <slug>/ has .md files?     → auto-generated directory listing
5. otherwise                  → 404

A path with a non-Markdown extension — /style.css, /images/photo.jpg — is looked up directly and served as-is, with its media type guessed from the extension.

Legacy .html URLs

Static generators with "ugly URLs" publish pages as /<slug>.html. When such a request matches no file but the Markdown source exists, Everlock answers 302 to the extensionless route, so inbound links survive a migration without per-page redirects:

GET /<slug>.html       (no such file)
  <slug>.md exists?                          → 302 /<slug>
GET /<dir>/index.html  (no such file)
  <dir>/index.md or <dir>/_index.md exists?  → 302 /<dir>

A literal .html file in the store always wins; the fallback runs only when the requested file is absent.

Content negotiation

Every rendered page has two representations at one URL: the HTML its layout produces, and the page's own Markdown source. The client picks with Accept:

GET /bike
Accept: text/markdown, text/html, */*

200 OK
Content-Type: text/markdown; charset=utf-8
Vary: Accept

This follows the convention described at acceptmarkdown.com: a page that has a Markdown source should be able to hand it over when asked, rather than making a reader — or an agent — parse prose back out of markup.

What the Markdown representation is. The source after front matter removal and shortcode expansion — the same text the HTML renderer consumes. Shortcodes that expand to HTML remain as inline HTML. When the front matter carries a title and the body does not open with a level-one heading, the title is emitted as a leading # heading.

How the choice is made. Selection follows RFC 9110 quality values: Markdown is served when text/markdown is named explicitly, with a q at least equal to the one text/html resolves to. Wildcards (*/*, text/*) never select Markdown, so browsers and a plain curl keep getting HTML. Both representations carry Vary: Accept, so shared caches keep them apart.

Where it applies. Page routes only — /<slug>, /<slug>.md, and /<dir>/ resolving to index.md. Files served as-is, directory listings, feeds, the search index and output-format variants ignore Accept. HTML-mode sites have one representation per file and ignore it too.

Draft and future-dated rules apply to both representations: a page that is not published yet is not published in either form.

Paths that are never served

These return 404 whatever the store holds, because they are project configuration rather than content:

PathReason
site.tomlSite config
layouts/*Templates
shortcodes/*Shortcode templates

Hidden directories and anything named in ignore_dirs are excluded the same way — see Structure.

404 responses

When no route matches, a Markdown-mode site renders layouts/404.html if the repository provides one — an ordinary Tera template that may extend base.html — served with status 404 and the usual site, page, data and all_pages context, where page.title is Page not found and page.path is what was requested. Without that template, and always in HTML mode, the response is plain text.

site routing markdown http