Skip to content
Blume
Esc
↑↓navigate↵open⌘Jpreview
On this page

Includes

Reuse content across pages — splice shared Markdown, MDX, or code files into any page with the include syntax.

Write a snippet once and splice it into any page. An <include> statement on its own line embeds another file at build time, as if its content were written inline — headings join the page’s table of contents, text is indexed by search, and the content appears in the page’s .md mirror and llms-full.txt. A statement a formatter wraps across lines still splices, and one Blume can’t parse raises a BLUME_INCLUDE_MALFORMED warning at its line instead of rendering as a raw tag.

<include>./_snippets/prerequisites.mdx</include>

The path is resolved relative to the including file. Paths starting with / resolve from your content root, so deeply nested pages can reference shared snippets without ../../.. chains:

<include>/_snippets/prerequisites.mdx</include>

The syntax matches Fumadocs’ include syntax, so migrated content works unchanged.

Here it is live — this next callout is spliced from a shared snippet:

Partials

Any file whose name (or folder) starts with an underscore is excluded from routing, navigation, search, and sitemaps — that convention is the natural home for shared snippets. Patterns you add to content.exclude add to this rule rather than replacing it; to publish underscore files after all, add "!**/_*" to exclude:

docs/
  _snippets/
    prerequisites.mdx
    cli-flags.md
  guides/
    quickstart.mdx   ← <include>../_snippets/prerequisites.mdx</include>
  index.mdx

A partial is a normal Markdown or MDX file. Its front matter is stripped when spliced (the including page’s front matter wins), and everything else — callouts, code fences, components, math — renders exactly as it would inline. Partials can include other partials; a circular include is reported as an error.

Link reference definitions ([pep 508]: https://peps.python.org/pep-0508/) cross includes too, so a partial can hold a site’s shared link definitions: the page and its other partials can cite a partial’s ([PEP 508]), and a partial can cite the page’s. When the page and a partial both define a label, each uses its own.

Relative image references inside a partial keep working: they’re rebased onto the including page, so a colocated ![diagram](./diagram.png) or <Card img="./cover.png"> next to the partial resolves wherever the partial is spliced. An image’s path is rebased in whatever form it’s written: in angle brackets (![diagram](<./my diagram.png>)), with escaped parentheses, or followed by a title in any of its quotes. A link to another file next to the partial ([spec](./spec.pdf), or an <img src> or <a href> naming one) moves with it too. A link to a page resolves from the including page, as if it were written there.

Editing a partial while blume dev is running reloads every page that includes it.

Props

Pass values into a partial as attributes, and read them in the partial with {{name}}, the same syntax as variables. One partial then serves every page that needs a variation of it:

Upgrade to the **{{plan}}** plan to use {{feature}}.
<include plan="Enterprise" feature="SSO">
  ./_snippets/upgrade.mdx
</include>

A prop applies to the included file and to anything it includes in turn, and takes precedence over a site-wide variable with the same name. Every attribute except lang and meta is a prop; attribute names are lowercase, and values are quoted plain text. Props reach Markdown and MDX partials only: a {{name}} in an included code file isn’t replaced by a prop.

Including code files

A target that isn’t .md/.mdx is embedded as a fenced code block, with the language inferred from the extension. Use lang to override the language (or to show a Markdown file as source rather than splicing it), and meta to pass a fence meta string such as a title:

<include>./examples/config.ts</include>

<include meta='title="config.ts"'>./examples/config.ts</include>

<include lang="mdx">./_snippets/prerequisites.mdx</include>

Rules and diagnostics

Include statements must occupy their own line — they’re block-level, not inline. Statements inside fenced code blocks are left alone, so you can document the syntax itself (like this page does).

Targets must live inside your content root: a file outside it would be silently missing from version snapshots and ejected projects, so blume reports BLUME_INCLUDE_OUTSIDE_ROOT instead of splicing it. A target that doesn’t exist is BLUME_INCLUDE_NOT_FOUND, and a loop of includes is BLUME_INCLUDE_CYCLE — all three fail blume build (pass --no-strict to build anyway) and appear in blume validate.

Broken links inside a partial are reported against the partial file, not the pages that splice it, so you fix them where they live.

A partial is read in the including page’s format, so a .md partial that an .mdx page includes is read as MDX. MDX has no HTML comments, so the partial’s <!-- … --> comments are spliced as MDX comments ({/* … */}) and stay hidden. Other HTML there has to be valid JSX: an <img …> or <br> without a closing slash takes in everything after it in the partial, with no error. Blume warns about it as BLUME_MDX_UNCLOSED_ELEMENT at the partial’s line; close it as <br />. Anything else in the partial that MDX can’t parse once it’s spliced in, like a stray {, is a BLUME_MDX_SYNTAX warning at the partial’s line, and when it fails the build, the build reports it there too, not at the page that includes it.

Last updated on

Was this page helpful?