Template Functions (J2/Jinja2)
Render Jinja2-compatible templates with data. These functions enable workflows to transform structured data into formatted text using loops, conditionals, filters, and variable substitution.
Overview
The template integration provides two functions powered by Nunjucks (Mozilla's JavaScript implementation of Jinja2):
renderTemplate()- Render a template with explicit datarenderTemplateFromContext()- Render using all available context variables
Why Use Templates?
Templates are ideal for:
- Formatting LLM responses into human-readable text
- Building social media posts from structured data
- Creating notifications with dynamic content
- Generating reports from arrays of data
- Conditional formatting based on data values
Functions
renderTemplate
Render a Jinja2/Nunjucks template string with provided data.
Signature:
async function renderTemplate(
template: string,
data: object
): Promise<string>
Parameters:
| Parameter | Type | Description |
|---|---|---|
template | string | J2 template string with variables and control structures |
data | object | Data object for template variable substitution |
Returns: Rendered string output
Example:
const template = "Hello {{ name }}! You have {{ count }} messages.";
const result = await renderTemplate(template, { name: "David", count: 5 });
// Result: "Hello David! You have 5 messages."
renderTemplateFromContext
Render a template using all available variables from the workflow context.
Signature:
async function renderTemplateFromContext(
template: string
): Promise<string>
Available Context Variables:
| Variable | Description |
|---|---|
| Workflow fields | Same names as script globals (type, content, user, payload, …) |
latestPromptResponse | Raw response from the last Prompt entity |
promptData | Parsed JSON from the last Prompt entity (if valid JSON) |
stm | Short-term memory object |
{variableName} | All variables from Admin Console Settings |
Example:
// Assumes a Prompt entity returned JSON with teams array
const template = `
{% for team in promptData.teams %}
- {{ team.name }}
{% endfor %}
`;
const result = await renderTemplateFromContext(template);
Template Syntax Reference
Variables
Access data using double curly braces:
const template = `
Name: {{ user.name }}
Email: {{ user.email }}
Role: {{ user.profile.role }}
First item: {{ items[0] }}
`;
Conditionals
Use {% if %}, {% elif %}, {% else %}:
const template = `
{% if score >= 90 %}
Grade: A
{% elif score >= 80 %}
Grade: B
{% elif score >= 70 %}
Grade: C
{% else %}
Grade: F
{% endif %}
`;
Loops
Iterate over arrays with {% for %}:
const template = `
{% for player in players %}
{{ loop.index }}. {{ player.name }} - {{ player.position }}
{% endfor %}
`;
Loop Variables:
| Variable | Description |
|---|---|
loop.index | Current iteration (1-indexed) |
loop.index0 | Current iteration (0-indexed) |
loop.first | True if first iteration |
loop.last | True if last iteration |
loop.length | Total number of items |
Filters
Transform values with pipe syntax:
const template = `
{{ name | upper }} // JOHN
{{ name | lower }} // john
{{ name | capitalize }} // John
{{ items | length }} // 5
{{ items | first }} // First item
{{ items | last }} // Last item
{{ items | join(", ") }} // a, b, c
{{ value | default("N/A") }} // Fallback if undefined
{{ text | trim }} // Remove whitespace
{{ items | sort }} // Sort array
{{ number | round(2) }} // Round to 2 decimals
`;
Comments
Add non-rendered comments:
const template = `
{# This is a comment and won't appear in output #}
{{ name }}
`;
Complete Examples
Example 1: Format Sports Data for Social Media
Transform structured LLM output into a Mastodon-ready post:
Prompt Entity Output (JSON):
{
"teams": [
{ "name": "Ravens", "market": "Baltimore", "wins": 10, "losses": 3, "playoffs": true },
{ "name": "Chiefs", "market": "Kansas City", "wins": 9, "losses": 4, "playoffs": true }
],
"summary": "AFC playoff race heating up!"
}
Action Script:
// Get and parse the LLM response
const response = await latestPromptResponse();
const data = JSON.parse(response.replace(/'/g, '"'));
// Define template for Mastodon post
const template = `
🏈 NFL Update: {{ summary }}
{% for team in teams %}
{{ team.market }} {{ team.name }}: {{ team.wins }}-{{ team.losses }}{% if team.playoffs %} ✅{% endif %}
{% endfor %}
#NFL #Football #Sports
`;
// Render and post
const formatted = await renderTemplate(template, data);
await postToMastodon(MASTODON_URL, MASTODON_ACCESS_TOKEN, formatted.trim());
print('Posted to Mastodon!');
Output:
🏈 NFL Update: AFC playoff race heating up!
Baltimore Ravens: 10-3 ✅
Kansas City Chiefs: 9-4 ✅
#NFL #Football #Sports
Example 2: Build Dynamic Notification
Action Script:
const template = `
{% if priority == "high" %}
🚨 URGENT: {{ title | upper }}
{% else %}
📢 {{ title }}
{% endif %}
{{ body }}
{% if actions and actions | length > 0 %}
Actions:
{% for action in actions %}
- {{ action }}
{% endfor %}
{% endif %}
Sent: {{ timestamp | default("now") }}
`;
const result = await renderTemplateFromContext(template);
print(result);
Example 3: Generate Report from Array
Action Script:
const data = {
title: "Weekly Sales Report",
date: "2026-01-20",
items: [
{ product: "Widget A", quantity: 150, revenue: 4500 },
{ product: "Widget B", quantity: 89, revenue: 2670 },
{ product: "Widget C", quantity: 234, revenue: 7020 }
],
totalRevenue: 14190
};
const template = `
📊 {{ title }}
Date: {{ date }}
${"=".repeat(40)}
{% for item in items %}
{{ loop.index }}. {{ item.product }}
Qty: {{ item.quantity }} | Revenue: ${{ item.revenue }}
{% endfor %}
${"=".repeat(40)}
💰 Total Revenue: ${{ totalRevenue }}
`;
const report = await renderTemplate(template, data);
print(report);
Example 4: Conditional Content with Fallbacks
Action Script:
const template = `
Player: {{ player.name | default("Unknown") }}
Team: {{ player.team | default("Free Agent") }}
Position: {{ player.position | default("N/A") }}
{% if player.stats %}
Stats:
- Touchdowns: {{ player.stats.touchdowns | default(0) }}
- Yards: {{ player.stats.yards | default(0) }}
{% else %}
Stats not available.
{% endif %}
{% if player.injured %}
⚠️ Currently on injured reserve
{% endif %}
`;
const result = await renderTemplate(template, {
player: {
name: "Lamar Jackson",
team: "Baltimore Ravens",
position: "QB",
stats: { touchdowns: 24, yards: 3678 }
}
});
print(result);
Example 5: Using Context Variables
Use all available context without passing explicit data:
Action Script:
// This template uses automatic context variables
const template = `
Processing message from: {{ source | default("unknown") }}
Organization: {{ ORGANIZATION_NAME | default("N/A") }}
{% if promptData %}
AI Response Summary:
{{ promptData.summary | default(latestPromptResponse) }}
{% endif %}
{% if stm.lastProcessed %}
Previous: {{ stm.lastProcessed }}
{% endif %}
`;
const result = await renderTemplateFromContext(template);
print(result);
// Store for next message
stmSet('lastProcessed', new Date().toISOString());
Example 6: Nested Data Structures
Action Script:
const data = {
tournament: {
name: "AFC Championship",
teams: {
home: { name: "Ravens", city: "Baltimore", seed: 1 },
away: { name: "Bills", city: "Buffalo", seed: 2 }
},
venue: {
name: "M&T Bank Stadium",
city: "Baltimore",
capacity: 71008
}
}
};
const template = `
🏟️ {{ tournament.name }}
{{ tournament.teams.away.city }} {{ tournament.teams.away.name }} (#{{ tournament.teams.away.seed }})
@
{{ tournament.teams.home.city }} {{ tournament.teams.home.name }} (#{{ tournament.teams.home.seed }})
📍 {{ tournament.venue.name }}
{{ tournament.venue.city }} ({{ tournament.venue.capacity | string }} capacity)
`;
const result = await renderTemplate(template, data);
print(result);
Example 7: Combining with LLM Output
A complete workflow pattern:
Prompt Entity:
Analyze this game event and return JSON with:
- summary: one sentence summary
- sentiment: positive/negative/neutral
- highlights: array of key points
Event: {{event}}
Action Script (following the Prompt):
// Parse the LLM response
const response = await latestPromptResponse();
let analysis;
try {
analysis = JSON.parse(response.replace(/'/g, '"'));
} catch (e) {
print('Failed to parse LLM response:', e.message);
return;
}
// Format for different outputs
const socialTemplate = `
{{ summary }}
{% for highlight in highlights %}
• {{ highlight }}
{% endfor %}
#GameDay
`;
const notificationTemplate = `
{% if sentiment == "positive" %}🎉{% elif sentiment == "negative" %}😔{% else %}📢{% endif %} {{ summary }}
`;
// Generate both
const socialPost = await renderTemplate(socialTemplate, analysis);
const notification = await renderTemplate(notificationTemplate, analysis);
// Use them
await postToMastodon(MASTODON_URL, MASTODON_ACCESS_TOKEN, socialPost.trim());
print('Notification:', notification);
// Pass to next entity
output = { socialPost, notification, sentiment: analysis.sentiment };
Tips & Best Practices
- Trim output - Use
.trim()on results to remove extra whitespace - Use default filter - Prevent undefined errors with
{{ value | default("fallback") }} - Parse LLM output - Remember to
JSON.parse()the prompt response before passing to template - Handle single quotes - LLMs sometimes return Python-style single quotes; use
response.replace(/'/g, '"')before parsing - Test templates - Use
print()to verify output before posting to external services - Keep templates readable - Use multi-line template literals for complex templates
Troubleshooting
"Template rendering failed"
Cause: Syntax error in template
Solution:
- Check for unclosed tags (
{% if %}without{% endif %}) - Verify variable names match your data structure
- Check filter syntax (e.g.,
| join(",")not| join ,)
Undefined variables appearing as empty
Cause: Variable path doesn't exist in data
Solution:
- Use default filter:
{{ value | default("N/A") }} - Check data structure with
print(JSON.stringify(data))
Template output includes raw template syntax
Cause: Template not being rendered (likely a typo in function name)
Solution:
- Ensure you're using
await renderTemplate()orawait renderTemplateFromContext() - Check that the template string is passed correctly
Related Topics
- Prompt Functions - Get LLM responses to format
- Mastodon Functions - Post formatted content
- Print Functions - Debug template output
- STM Functions - Store rendered content for later use