Forge includes two template functions for rendering content: forge_markdown and forge_html. They solve different problems and have different security models. Knowing when to use each one matters.
forge_markdown
Used on fields where authors write in markdown -- with the option to drop raw HTML blocks into the same field.
{{ forge_markdown .Body }}
The renderer processes markdown syntax normally. Lines that start with < are emitted verbatim -- they bypass the markdown renderer and go straight to output. This means an author can write an article in markdown and embed custom HTML blocks in the same field:
Forge handles content lifecycle at the framework level.
<div class="terminal-block">
<span class="prompt">$</span> forge-cli publish my-post
</div>
The publish command transitions the content from Draft to Published.
The markdown sections render as prose. The HTML block is passed through as-is. No special delimiter, no separate field.
forge_html
Used when a field already contains rendered HTML and you want to output it directly in a template without Go's template engine escaping it.
{{ forge_html .RenderedContent }}
Go templates HTML-escape output by default. forge_html marks the string as trusted and bypasses escaping. Use this when a field stores pre-rendered content -- from an external system, a migration, or a field that is maintained as HTML directly.
The difference
| forge_markdown | forge_html | |
|---|---|---|
| Input format | Markdown with optional HTML blocks | Already-rendered HTML |
| HTML passthrough | Lines starting with < emitted verbatim | Entire field emitted verbatim |
| Use case | Author-written content | Pre-rendered or imported content |
A practical example: a tech article with inline terminal blocks uses forge_markdown. A field populated by an import script that produces HTML uses forge_html.
Security model
Neither function sanitizes its input. Both emit content verbatim.
This is intentional. Forge is self-hosted. Content authors are trusted operators -- not anonymous public contributors on a multi-tenant platform. The security model matches the deployment model.
If you are building something where untrusted users submit content, sanitize before storage -- not at render time.
The rendering pipeline
The same content that renders in the browser via these template functions also feeds the AI-readable formats. .aidoc responses and /llms-full.txt draw from the same content fields. Consistent rendering at the source means consistent content across all four delivery channels -- browser, API, and both AI layers.