This document describes conventions for Tera templates that generate YAML files in the Torrust Tracker Deployer project.
See Also: For general Tera template syntax, see Tera Template Guide. For architectural details, see Template System Architecture.
CRITICAL: For YAML templates (both .yml.tera and static .yml files), the AI-discoverable documentation header MUST be placed BEFORE the --- YAML document marker.
# ============================================================================
# Torrust Tracker Deployer - Generated Configuration
# ============================================================================
#
# This file was generated by the Torrust Tracker Deployer.
# Generated at: {{ generated_at }}
#
# DOCUMENTATION:
# Repository: https://github.com/torrust/torrust-tracker-deployer
# Template: templates/ansible/variables.yml.tera
# Rust Wrapper: src/infrastructure/templating/ansible/template/wrappers/variables/context.rs
# API Docs: https://docs.rs/torrust-tracker-deployer/latest/
#
# DESCRIPTION:
# Centralized Ansible variables used across playbooks for system configuration.
#
# For configuration options and valid values, see the API documentation link above.
# ============================================================================
---
# YAML content starts here
variable_name: { { value } }---
# ❌ WRONG - Header after the document marker
# ============================================================================
# Torrust Tracker Deployer - Generated Configuration
# ============================================================================The --- marker in YAML indicates the start of a YAML document. The header contains metadata about the file (repository links, generation info, documentation), not YAML content. Therefore:
- Header = Metadata → Comes first
---= Document Start → Comes after metadata- YAML Content → Comes after document marker
This convention ensures:
- Clear separation between metadata and content
- Consistency across all YAML templates (dynamic
.teraand static) - Proper YAML document structure
- AI agents can discover documentation before parsing YAML
Dynamic Templates (.yml.tera):
templates/ansible/variables.yml.teratemplates/ansible/inventory.yml.teratemplates/grafana/provisioning/datasources/prometheus.yml.teratemplates/prometheus/prometheus.yml.teratemplates/tofu/common/cloud-init.yml.tera
Static Templates (.yml):
templates/ansible/configure-firewall.ymltemplates/ansible/configure-security-updates.ymltemplates/ansible/create-grafana-storage.yml- And all other Ansible playbooks...
When using Tera control flow in YAML templates, use {%- to prevent inserting extra blank lines:
# ✅ GOOD - No extra blank lines
services:
{%- if mysql_enabled %}
mysql:
image: mysql:8.0
{%- endif %}
{%- if grafana_enabled %}
grafana:
image: grafana/grafana:latest
{%- endif %}# ❌ BAD - Creates blank lines between services
services:
{% if mysql_enabled %}
mysql:
image: mysql:8.0
{% endif %}
{% if grafana_enabled %}
grafana:
image: grafana/grafana:latest
{% endif %}Result of bad approach:
services:
mysql:
image: mysql:8.0
grafana:
image: grafana/grafana:latestYAML is indentation-sensitive. When using conditionals, ensure proper indentation:
# ✅ CORRECT - Maintains proper YAML indentation
networks:
{%- if database_enabled %}
db_network:
driver: bridge
{%- endif %}
{%- if metrics_enabled %}
metrics_network:
driver: bridge
{%- endif %}When generating YAML lists with Tera:
# ✅ CORRECT - Consistent list formatting
hosts:
{%- for host in inventory_hosts %}
- name: {{ host.name }}
address: {{ host.ip }}
{%- endfor %}YAML supports multi-line strings. Be careful with Tera variable placement:
# ✅ CORRECT - Preserves YAML multi-line syntax
description: |
{{ service_description }}
Additional context goes here.
# ✅ CORRECT - Folded scalar
summary: >
{{ short_summary }}
continues on next line# ❌ WRONG
---
# Header comments after document markerFix: Move header before ---
# ❌ WRONG
{% if condition %}
key: value
{% endif %}Fix: Use {%- and -%} for whitespace control
# ❌ WRONG - Incorrect indentation
parent:
{% if condition %}
child: value
{% endif %}Fix: Maintain consistent indentation inside control blocks
# ❌ RISKY - May break if variable contains YAML special chars
description: {{ user_description }}
# ✅ SAFER - Quote the value
description: "{{ user_description }}"Always check the rendered YAML in the build/ directory:
# Check rendered Ansible variables
cat build/your-env/ansible/variables.yml
# Validate YAML syntax
yamllint build/your-env/ansible/variables.ymlAdd comments to explain configuration options:
# Set to true when ANY HTTP tracker uses Caddy TLS termination
caddy_enabled: { { caddy_enabled } }
# HTTP tracker external port (must match your Caddy configuration)
http_tracker_port: { { http_tracker_port } }Organize YAML content logically:
# Database Configuration
mysql_enabled: { { mysql_enabled } }
mysql_root_password: "{{ mysql_root_password }}"
# Monitoring Configuration
prometheus_enabled: { { prometheus_enabled } }
grafana_enabled: { { grafana_enabled } }- Use
{%-at start of control flow to trim preceding whitespace - Use
-%}at end only when needed to prevent trailing blank lines - Test rendered output to ensure no extra blank lines