The problem: repeated content shouldn't live in every file that needs it
A shared disclaimer, a common install-step callout, a footer, these show up on many pages of a docs site. Copy-pasting them into every source file means every edit has to happen N times. Markdoc's {% partial %} tag lets one document include another, but with a twist: Markdoc itself never touches the filesystem. Resolving file="..." to actual content is entirely your code's responsibility.
The code, piece by piece
const partialSource = fs.readFileSync(path.join(FIXTURES_DIR, partialPath), "utf8");const partialAst = Markdoc.parse(partialSource);Reading the partial's file and parsing it happens exactly the same way as any other document, Markdoc.parse doesn't have a special "this is a partial" mode.
const config = { tags: { callout }, partials: { [partialPath]: partialAst },};config.partials is a plain map: the exact string used in the source's file="..." attribute, mapped to that file's already-parsed Ast. When transform encounters {% partial file="partials/callout.md" /%}, it looks up config.partials["partials/callout.md"], if that key isn't there, the partial silently resolves to nothing during a render, but Markdoc.validate (below) reports it as a real error.
{% partial file="partials/callout.md" /%}Note the trailing /%}, partial is a self-closing tag (it has no children of its own, it's replaced entirely by whatever the referenced file contains), Markdoc's own built-in tag schema for partial marks it selfClosing: true.
const errors = Markdoc.validate(ast, { tags: { callout } });Validating the same document without config.partials set reproduces exactly the "Partial not found" error a CI check would catch, this is what makes a missing or renamed partial a build-time failure instead of a silently broken page.
Checkpoint
{% partial file="..." /%}: a self-closing built-in tag that includes another document's content inline.- Markdoc does zero filesystem I/O:
config.partialsmust already contain every referenced file's parsedAst, resolving paths and reading files is entirely host code, exactly like the frontmatter parsing in Lesson 5. - A missing partial is a validation error, not a silent gap:
Markdoc.validatereportsattribute-value-invalidwith a clear message when afileisn't inconfig.partials, catchable in CI before a broken page ships.
If anything here still feels unclear, ask before moving to Lesson 12.