Skip to main content
Stop copy-pasting prompts across your codebase. Templates let you define a prompt once, use it everywhere, and track every change automatically.
Template editor in Studio
Why templates?
  • Write dynamic prompts with variables, loops, and conditionals
  • Catch errors early with typed, validated inputs
  • Roll back to any previous version instantly
  • Share common snippets across templates with parts

Built-in Templates

Every new project includes ready-to-use templates:
TemplateDescription
faq_responderAnswer FAQ questions using a knowledge base with source citations
research_synthesizerSynthesize multiple sources into a cohesive summary
technical_documentationGenerate comprehensive docs with code examples
social_media_campaignCreate multi-platform social media posts from a brief
Open any built-in template in the Studio to see how it uses parts, loops, and typed inputs. Then duplicate and customize it for your use case.

Creating Templates

1

Navigate to Library

Go to LibraryPrompts in the sidebar and click New Prompt.
2

Write Your Template

Write your prompt using {{ variable }} placeholders for dynamic content.
Answer the following question using the provided knowledge base.

Question: {{ question }}
Knowledge Base: {{ knowledge_base }}
Tone: {{ tone }}
3

Define Variables

In the Variables panel, add each variable with its type and default value.
4

Test in Playground

Use the built-in playground to test with sample inputs before saving.
5

Save

Click Save to make the template available via SDK.

Inputs

Inputs are typed variables that make your templates dynamic. Define them when creating a template:
inputs={
    "question": {"type": "string", "required": True},
    "sources": {"type": "array<string>", "required": True},
    "max_sources": {"type": "number", "default": 5},
    "include_citations": {"type": "boolean", "default": True},
}
Supported types: string, number, boolean, array<string>, and object.
Dakora validates inputs at render time. Missing required inputs or type mismatches fail fast with clear error messages.

Jinja2 Syntax

Dakora uses Jinja2, a popular Python templating engine, to make your prompts dynamic. Use {{ variable }} for inserting values, {% if %} for conditionals, and {% for %} for loops.
Question: {{ question }}
Knowledge Base: {{ knowledge_base }}

Parts (Reusable Snippets)

Parts are reusable prompt snippets that can be included in any template. Every project comes with built-in parts you can use immediately.

Built-in Parts

PartCategoryWhat it does
system_rolesystem_rolesSets the AI persona: “You are a helpful AI assistant.”
json_outputformattingInstructs JSON-formatted responses
markdown_listformattingFormats output as markdown lists
chain_of_thoughtreasoningEnables step-by-step reasoning
citation_formatguidelinesStandardizes citation formatting

Including Parts

Use Jinja2’s {% include %} directive with the path category/part_id:
{% include "system_roles/system_role" %}

Task: Answer the following FAQ question.

Question: {{ question }}

{% include "formatting/json_output" %}

Creating Your Own Parts

In the Studio, go to LibraryParts:
  1. Click New Part
  2. Set a Part ID (e.g., company_context)
  3. Choose a Category (e.g., context)
  4. Write the reusable prompt content
  5. Save and use with {% include "context/company_context" %}

Versioning

Every save creates a new version automatically. Templates start at version 1, and each save increments the number. Content hashing prevents duplicate versions.

Pinning Versions

By default, render() uses the latest version. In production, pin to a tested version:
result = await client.prompts.render(
    "faq_responder",
    {"question": "How do I upgrade?", "knowledge_base": "..."},
)

Rolling Back

In the Studio, open any template → click History → select a version → Restore. Rolling back creates a new version with the old content, preserving the audit trail.

Rendering Templates

Rendering takes a template and fills in its variables with your inputs, resolves any included parts, and returns a complete prompt string ready to send to any LLM.
In the Studio, you can test rendering in two ways:
  1. Preview Panel: Shows your template with parts resolved, but variables remain as {{ placeholders }} so you can see the structure.
  2. Test Panel: Fill in input values, select an LLM model, and run the template end-to-end. This renders the template AND sends it to the LLM, showing you the actual response.
Testing a template in Studio

RenderResult

FieldDescription
textThe rendered prompt ready for your LLM
prompt_idTemplate identifier
versionSemantic version used
version_numberNumeric version (1, 2, 3…)
inputsThe inputs that were provided
By default, Dakora embeds tracking metadata: <!--dakora:prompt_id=faq_responder,version=1.0.0-->. This enables automatic linking of LLM executions back to templates. Disable with embed_metadata=False.

Common Patterns

These patterns appear frequently in production templates:
Show or hide entire sections based on a flag:
{{ task_description }}

{% if include_examples %}
Examples:
{% for example in examples %}
- {{ example }}
{% endfor %}
{% endif %}

{% if strict_mode %}
Important: Follow the format exactly. Do not deviate.
{% endif %}

Best Practices

Choose clear, descriptive template IDs:
  • faq_responder, research_synthesizer, social_media_campaign
  • template1, v2_final_new
If you’re copying the same text across templates, extract it as a part:
{# Before: duplicated in every template #}
You are a helpful AI assistant.

{# After: use a part #}
{% include "system_roles/system_role" %}
Type definitions catch errors early:
inputs={
    "question": {"type": "string", "required": True},
    "sources": {"type": "array<string>", "required": True},
    "max_sources": {"type": "number", "default": 5},
}
result = await client.prompts.render(
    "faq_responder",
    inputs,
    version="5",  # Pin to tested version
)
Use the Playground to test templates before making them live.

Reference

Template Fields:
FieldRequiredDescription
idYesUnique identifier (e.g., faq_responder)
templateYesThe prompt text with Jinja2 syntax
descriptionNoHuman-readable description
inputsNoTyped variable definitions with defaults
versionAutoSemantic version string (e.g., 1.0.0)
metadataNoCustom metadata (tags, author, etc.)
Input Types: string, number, boolean, array<string>, object

Next Steps

Now that you understand templates: