Template Syntax & Variables
Mustache template syntax for prompt variables, conditionals, loops, and nested objects across TypeScript, Python, and Java SDKs.
Template Syntax & Variables
Prompts use Mustache templating syntax. Variables are delimited by double curly braces and are resolved by calling .compile() with a map of values.
Basic Variable Syntax
{{variable}}The simplest case: replace a named placeholder with a string value.
// Template: "Summarize the following text in {{language}}: {{text}}"
const compiled = prompt.compile({
language: 'French',
text: 'Paris is the capital of France.',
});
// → "Summarize the following text in French: Paris is the capital of France."# Template: "Summarize the following text in {{language}}: {{text}}"
compiled = prompt.compile(
language="French",
text="Paris is the capital of France.",
)
# → "Summarize the following text in French: Paris is the capital of France."// Java SDK does not provide a Mustache compile() method.
// Substitute variables manually using string replacement.
PromptResponse prompt = prompts.get("summarizer");
String template = (String) prompt.getPrompt();
String compiled = template
.replace("{{language}}", "French")
.replace("{{text}}", "Paris is the capital of France.");Dataset Variables ($ prefix)
When you run an experiment, your prompt runs against every item in a dataset. Instead of hardcoding values, use $ variables to tell the platform which part of each dataset item to insert into the prompt automatically.
Regular variables ({{name}}) are filled by your code via compile(). Dataset variables ({{$input.field}}) are filled by the platform during experiment and dataset runs — you never need to pass their values manually.
How it works
Say your dataset has this item:
{
"input": { "question": "What is the capital of France?", "language": "French" },
"expectedOutput": { "answer": "Paris" },
"metadata": { "difficulty": "easy" }
}And your prompt template is:
Answer the following question in {{$input.language}}:
{{$input.question}}When the experiment runs, the platform resolves each $ variable from the dataset item and produces:
Answer the following question in French:
What is the capital of France?Available columns
The $ prefix only works with the five reserved dataset columns:
| Column | Variable examples | Description |
|---|---|---|
input | {{$input}}, {{$input.question}} | The item's input data |
output | {{$output}}, {{$output.text}} | The item's output data |
expectedOutput | {{$expectedOutput}}, {{$expectedOutput.answer}} | The expected output for evaluation |
metaData | {{$metaData}}, {{$metaData.difficulty}} | Additional metadata |
context | {{$context}}, {{$context.source}} | Context for retrieval-augmented generation |
Snake-case aliases {{$expected_output}} and {{$metadata}} also work.
Whole column vs nested field
Use the column name alone to get the entire value, or dot notation to drill into nested fields:
{{$input}} → entire input column (stringified if it's an object)
{{$input.question}} → just the "question" field
{{$input.user.name}} → nested access into deeper objectsConditional blocks
Wrap a section in {{#$column.field}}...{{/$column.field}} to only render it when the field is truthy:
{{#$metaData.include_context}}
Use this additional context: {{$context}}
{{/$metaData.include_context}}If metaData.include_context is missing, empty, or false, the entire block is skipped.
Mixing regular and dataset variables
You can use both types in the same prompt. Regular variables are resolved by compile(), and $ variables are resolved from the dataset at run time:
You are a {{role}} assistant.
Answer this question: {{$input.question}}Here {{role}} is a regular variable you provide via compile(), while {{$input.question}} is pulled from each dataset item during the experiment.
Dashboard shortcut
In the prompt editor, click the Insert {{$input}} button to add a dataset variable. The Variables panel on the right automatically groups $ variables by their column (Input, Output, Expected Output, Metadata, Context).
Things to know
- Only works in experiments and dataset runs — if you call
prompt.compile()in your own code,$variables are not resolved and render as empty strings. - Only reserved columns are allowed —
{{$foo}}is invalid and raises an error. The$prefix must be followed by one of the five columns listed above. - Case-sensitive —
{{$metaData.difficulty}}and{{$metadata.difficulty}}both work (alias), but{{$MetaData.difficulty}}does not.
Nested Object Access
Use dot notation to access properties of nested objects.
{{user.name}}
{{config.model.temperature}}// Template: "Hello {{user.name}}, your plan is {{user.plan}}."
const compiled = prompt.compile({
user: { name: 'Alice', plan: 'pro' },
});
// → "Hello Alice, your plan is pro."# Template: "Hello {{user.name}}, your plan is {{user.plan}}."
compiled = prompt.compile(
user={"name": "Alice", "plan": "pro"},
)
# → "Hello Alice, your plan is pro."Conditional Sections
Render a block only when a value is truthy (non-empty string, non-zero number, non-empty list, or a dict):
{{#condition}}
This renders only when condition is truthy.
{{/condition}}// Template:
// "Analyze this data.{{#includeChart}} Include a chart.{{/includeChart}}"
const withChart = prompt.compile({ includeChart: true });
// → "Analyze this data. Include a chart."
const withoutChart = prompt.compile({ includeChart: false });
// → "Analyze this data."# Template:
# "Analyze this data.{{#include_chart}} Include a chart.{{/include_chart}}"
with_chart = prompt.compile(include_chart=True)
# → "Analyze this data. Include a chart."
without_chart = prompt.compile(include_chart=False)
# → "Analyze this data."Inverted Sections
Render a block only when a value is falsy (empty string, false, 0, empty list, or absent):
{{^condition}}
This renders only when condition is falsy.
{{/condition}}// Template: "{{^isExpert}}Please explain in simple terms.{{/isExpert}}"
const forNovice = prompt.compile({ isExpert: false });
// → "Please explain in simple terms."
const forExpert = prompt.compile({ isExpert: true });
// → ""# Template: "{{^is_expert}}Please explain in simple terms.{{/is_expert}}"
for_novice = prompt.compile(is_expert=False)
# → "Please explain in simple terms."
for_expert = prompt.compile(is_expert=True)
# → ""Loops / Iteration
Iterate over a list using a section tag. Inside the block, {{.}} refers to each list item, or use property names if items are objects:
{{#items}}{{name}}: {{value}}
{{/items}}// Template: "Available tools:\n{{#tools}}- {{name}}: {{description}}\n{{/tools}}"
const compiled = prompt.compile({
tools: [
{ name: 'search', description: 'Search the web' },
{ name: 'calculator', description: 'Perform arithmetic' },
],
});
// → "Available tools:\n- search: Search the web\n- calculator: Perform arithmetic\n"# Template: "Available tools:\n{{#tools}}- {{name}}: {{description}}\n{{/tools}}"
compiled = prompt.compile(
tools=[
{"name": "search", "description": "Search the web"},
{"name": "calculator", "description": "Perform arithmetic"},
]
)
# → "Available tools:\n- search: Search the web\n- calculator: Perform arithmetic\n"Common Pitfalls
Missing variable renders as empty string
If a variable is not passed to compile(), Mustache renders it as an empty string rather than raising an error:
Template: "Hello {{name}}!"
compile({}) → "Hello !"Always pass all variables your template references, or add {{^name}}default{{/name}} guards for optional fields.
Variable names are case-sensitive
{{UserName}} and {{username}} are different variables. Match the casing exactly between your template and your compile() call.
Sections vs. variables
A section tag {{#items}} is not the same as a variable tag {{items}}. Sections render their block; variables render the value inline. Using a list as a plain variable renders [object Object]-style output rather than iterating.