Variables

Any token of the form $NAME$ in the source is replaced at build time with the value declared in options.variables. Substitution runs as the final pass over the fully rendered page, so the same syntax reaches content, embedded files, and shell fragments like the logo and footer.

Syntax

A variable reference is a name in SCREAMING_SNAKE_CASE bracketed by dollar signs:

0.1.18
Carrot Search
$API_BASE_URL$

The name rules:

  • Must start with an uppercase letter.

  • May contain uppercase letters, digits, and underscores.

  • No lowercase — intentional, to keep the placeholders visually distinct from surrounding prose.

An unknown reference is left untouched, so an unreplaced $FOO$ will appear verbatim in the output. That makes stale references obvious in review rather than silently disappearing.

Configuration

Declare the map in eleventy.config.js:

import apidocs from "@carrotsearch/eleventy-apidocs";

export default async function (eleventyConfig) {
  return apidocs(eleventyConfig, {
    contentDir: "src/content",
    variables: {
      VERSION:      "0.1.0",
      SITE_OWNER:   "Carrot Search",
      API_BASE_URL: "https://api.example.com"
    }
  });
}

Values are coerced with String() on insertion, so numbers, booleans, and dates all work without ceremony. The build that produced this page used VERSION = "0.1.18" and SITE_OWNER = "Carrot Search" — the footer further down picks up the latter.

Where substitution applies

The variable pass is the last step in the document pipeline. By that point Nunjucks has already rendered the layout shell around the content, so any $NAME$ token anywhere in the resulting HTML is fair game — including in attribute values:

<p>Running version <code>0.1.18</code>.</p>
<a href="$API_BASE_URL$/healthz">Status</a>

The same applies to:

Article content

Every page under contentDir.

Logo and footer fragments

Both are rendered as raw HTML before substitution, so a footer like &copy; Carrot Search resolves correctly.

Embedded files

When a <pre data-embed> pulls in a file, substitution applies to that file’s contents too. The next section has an example.

Variables in embedded files

Substitution runs over embed contents as they’re loaded, before they’re inserted into the page. That lets a single config snippet pull values from the build:

export async function withVariables(eleventyConfig) {
  return apidocs(eleventyConfig, {
    contentDir: "src/content",
    variables: {
      VERSION: "0.1.18",
      OWNER: "Carrot Search"
    }
  });
}

When this page builds, the 0.1.18 and Carrot Search references inside the embed are resolved using the same map as the rest of the page — so the snippet readers see is the snippet the page itself was built with.

This isn’t a template language

Variable substitution is intentionally tiny: token replacement, no conditionals, no loops, no function calls. If you need branching or iteration in content, write a custom pipeline pass — the cheerio API gives you the full document to manipulate, which is a better tool for that job than a string-replace engine.