Skip to main content

Variables

4 min readStableIntermediate

Build-time {{vars.NAME}} placeholders resolve from owndocs.config.json or NEXT_PUBLIC_DOCS_VAR_* environment variables. lib/remark-vars.mjs rewrites the token while the page is still an mdast tree, so the rendered HTML carries the literal value and the browser never sees a placeholder.

Quick Start

One token in inline code, resolved from the vars object in owndocs.config.json.

The API base URL is https://api.example.com.

quick.mdx
MDX
The API base URL is `{{vars.apiUrl}}`.

Adding Options

Several tokens in the same sentence each resolve on their own, and the same substitution runs inside a fenced code block, so a sample request ships with the live values already filled in.

Welcome to OwnDocs version 1.0.0. The API base URL is https://api.example.com, and support@example.com reaches the support team.

status.sh
Bash
curl https://api.example.com/v1/status \
  -H "X-Brand: OwnDocs" \
  -H "X-Version: 1.0.0"
mixed.mdx
MDX
Welcome to `{{vars.brand}}` version `{{vars.version}}`. The API base URL is
`{{vars.apiUrl}}`, and `{{vars.supportEmail}}` reaches the support team.
 
```bash title="status.sh"
curl {{vars.apiUrl}}/v1/status \
  -H "X-Brand: {{vars.brand}}" \
  -H "X-Version: {{vars.version}}"
```

Advanced

A leading backslash keeps a token literal, and the backslash itself is eaten during substitution. A token whose name is not configured stays on the page untouched, which turns a typo into something a reviewer can see rather than a silent blank.

Escaped, this stays a token: {{vars.apiUrl}}. Unconfigured, this one also stays put: {{vars.missingKey}}.

escaping.mdx
MDX
Escaped, this stays a token: `\{{vars.apiUrl}}`. Unconfigured, this one also
stays put: `{{vars.missingKey}}`.

Where substitution reaches

The plugin walks text, inlineCode, and code nodes only. In an MDX page that comes down to two practical homes for a token: inline code and fenced code blocks, including fences that carry a language and a title meta. Inline code keeps working inside list items, blockquotes, and table cells.

Plain prose is the one that trips people up. MDX reads a bare pair of braces as a JavaScript expression and fails the compile before any remark plugin runs, so wrap a prose token in backticks and it works. Two other spots stay literal by design: a value passed to a component prop, and a link or image destination, which Next.js percent-encodes instead.

Snippets share the same variable context. components/Snippet.tsx calls getDocsVars() and passes it into the same plugin, so a fragment in snippets/ that names {{vars.brand}} resolves identically on every page that embeds it.

Defining the variables

lib/owndocs-config.ts reads owndocs.config.json from the project root, then layers environment variables on top. An environment variable wins when both define the same name.

owndocs.config.json
JSON
{
  "vars": {
    "apiUrl": "https://api.example.com",
    "supportEmail": "support@example.com",
    "version": "1.0.0",
    "brand": "OwnDocs"
  }
}
.env.local
Bash
NEXT_PUBLIC_DOCS_VAR_API_URL="https://api.staging.example.com"
NEXT_PUBLIC_DOCS_VAR_VERSION="1.1.0"

The environment name drops the NEXT_PUBLIC_DOCS_VAR_ prefix, lowercases what is left, and turns each underscore into a camel hump, so API_URL becomes apiUrl and SUPPORT_EMAIL becomes supportEmail.

A missing owndocs.config.json is fine and simply yields no file-defined variables. A file that is not valid JSON, or whose top level is not an object, throws a named error and stops the build. Inside the vars object, a key that does not match [a-zA-Z_][a-zA-Z0-9_]* is dropped, and only string, number, and boolean values survive; each one is coerced to a string before substitution. Nested objects, arrays, and null are ignored.

The merged result is cached in the module after the first read, so restart the dev server after editing owndocs.config.json or the environment file.

Options

{{vars.NAME}}token

Resolves from config or an environment variable inside inline code, a fenced code block, or any other text node MDX lets through. An unconfigured name renders unchanged.

\{{vars.NAME}}escaped

Keeps the token literal. The backslash is consumed and never reaches the page. Write two backslashes to show the escaped form itself inside a code block.

varsobject

The vars object in owndocs.config.json. Keys must match [a-zA-Z_][a-zA-Z0-9_]*; values must be a string, number, or boolean.

NEXT_PUBLIC_DOCS_VAR_*env

One variable per environment entry. The suffix is lowercased and converted to camelCase, and the value overrides a matching key from the config file.

Was this page helpful?