Write a page#
Goal: add one markdown file that renders with the right title, a table of contents, highlighted code and working links.
You need: a Content tree that already serves. The full key list and parser rules are in the content tree reference; the extension list is in the markdown reference.
Start with front-matter and an H1#
---
title: Roll back a deploy
weight: 30
description: Return a host to the previous release.
---
# Roll back a deploy
Front-matter is a block of key: value lines between two lines that are exactly ---. It is not
YAML: no lists, no nesting, no multi-line values. Five keys are read.
| Key | Effect |
|---|---|
title |
navigation label and <title>. Falls back to the first # heading, then the filename. |
weight |
position among siblings, lowest first. Default 100. |
draft |
true hides the page unless drafts are included. |
description |
the suffix of the page's llms.txt entry. |
updated |
an ISO date (2024-03-15) for the page's sitemap <lastmod>. Optional; a typo is ignored with a build warning. |
Put an H1 in the body too. The article title is the body's # heading, and the .md alternate of a
page without one gets a synthesised heading.
Use H2 and H3 for the table of contents#
## Stop traffic
### Drain the pool
## Restore the previous build
The "On this page" rail lists H2 and H3 headings only. H4 gets an anchor and a permalink but is not
listed. Every heading from H2 to H4 gets a # permalink.
Tag every code fence#
```bash
acme rollback web
```
Untagged fences render as plain preformatted text. The highlighter does not guess a language. Every fence gets a copy button.
To show a fence inside a fence, make the outer fence four backticks. A three-backtick outer fence is closed by the inner one and the rest of the example leaks out as headings and paragraphs.
Use a blockquote for a callout#
> Rolling back does not restore the database. See the restore guide.
Admonitions (!!! note) are not enabled and render as a paragraph. Tables, definition lists,
~~strikethrough~~ and ~subscript~ are enabled.
Link to another page#
Pages are served one level deeper than they are stored: how-to/deploy.md is served at
/docs/how-to/deploy/. Relative links start from the page's URL directory, not its file's
directory. End every link with a trailing slash.
| From a page in… | To a sibling | To a page in another Section |
|---|---|---|
a Section (how-to/deploy.md) |
](../rollback/) |
](../../reference/cli/) |
a Subsection (how-to/hosts/harden.md) |
](../provision/) |
](../../../reference/cli/) |
the root _index.md |
— | ](how-to/deploy/) |
Writing ](../how-to/rollback/) from how-to/deploy.md doubles the segment and 404s. Nothing
rewrites links and there is no redirect table. Moving a page breaks every link aimed at it until you
update them.
Add an image#
Put the image beside the page in the Content tree and reference it with a path relative to the page. mdjango serves it and rewrites the link to its URL — at runtime and in the static export:

The reference is relative to the page's own directory, so images/diagram.png and
../shared/logo.svg work too. Images out of the box means png, jpg/jpeg, gif, svg, webp
— widen or narrow that with MDJANGO_ASSET_EXTENSIONS. Any other file
type (and any .md) is left alone: it is not served, and a reference to it is emitted unchanged.
To make an image click to enlarge, link it to itself — a plain link, no JavaScript:
[](diagram.png)
Markdown is not a Django template: {% static %} is not evaluated in a page, and an absolute URL
(/static/… or https://…) is always emitted as written, so a shared asset your project already
serves still works.
Check the result#
python manage.py mdjango_build --check
This renders every page without writing and exits non-zero on a broken tree. See Validate content in CI.