← All tools

Jinja Template Renderer

Render an Ansible .j2 template against your variables — and see which ones are missing.

Why this exists

Every Ansible `template:` task goes through Jinja, and the usual loop for getting one right is ansible-playbook → wrong output → edit → rerun, with the whole inventory in the way. Paste the template and the group_vars beside it and the render is immediate. The list of undefined variables matters more than the output: that is the play that fails at 3 a.m. because one host had no override.

🔒 Runs in your browser — nothing is sent anywhere
template (.j2)
variables (YAML or JSON)
rendered
# managed by Ansible
upstream portfolio {
    server 10.0.0.51:8080;
    server 10.0.0.52:9000;
    server 10.0.0.53:8080 backup;
}

server {
    server_name opswithzaeem.com;

    listen 443 ssl http2;
    ssl_certificate     /etc/ssl/opswithzaeem.com.pem;

    location / {
        proxy_pass http://portfolio;
        proxy_set_header Host $host;
    }
}
Syntax reference — tags, filters, tests

Tags

{{ name }}
Insert a value.
{{ a.b.c }}
Walk a mapping. Also {{ list[0] }} and {{ list[0].host }}.
{% if x %} … {% elif y %} … {% else %} … {% endif %}
Branch.
{% for i in items %} … {% endfor %}
Repeat. {% else %} runs when the list is empty.
{% set n = 3 %}
Define a variable mid-template.
{# note #}
A comment. Renders nothing.
{%- … -%}
Eat the whitespace on that side — the fix for blank lines left by block tags.

Inside a for loop

loop.index
1, 2, 3 …
loop.index0
0, 1, 2 …
loop.first
true on the first pass
loop.last
true on the last — the usual way to skip a trailing comma
loop.length
how many items

Filters

default(v)
Use v when the variable is undefined. default(v, true) also replaces empty/false.
join(', ')
A list into a string.
upper / lower / capitalize / title
Case.
trim
Strip surrounding whitespace.
length
Items in a list, keys in a mapping, characters in a string.
replace(a, b)
Substring replacement.
int / float / string / bool
Convert. int takes a fallback: | int(0).
first / last / sort / unique / reverse / list
List handling.
indent(4)
Indent every line after the first — for nesting a block inside YAML.
tojson
Serialise, for embedding in JSON or a shell argument.

Tests and operators

x is defined
The Ansible idiom. Guard anything that might be absent.
x is not defined / is undefined
The negative.
x is none
Defined, but null. Not the same as undefined.
a in b
Membership in a list, mapping keys, or a substring.
and / or / not, == != > < >= <=
The usual operators.

The mistakes that actually cost time

  • An undefined variable fails the play. Ansible stops on it rather than rendering an empty string, so the warnings above are the real output of this tool. Guard anything optional with | default(...) or is defined.
  • default does not fire on an empty string. {{ name | default('anon') }} still renders nothing when name is "" — it is defined. Pass default('anon', true) to replace falsy values too.
  • Block tags leave blank lines. {% for %} on its own line emits that line's newline. Use {%- ... -%} to trim — it is why generated configs come out double-spaced.
  • A number in quotes is a string. port: "8080" compared with {% if port > 1024 %} behaves differently from an unquoted 8080. Use | int when you mean a number.
  • Whitespace matters in YAML output. When a template writes YAML, an interpolated multi-line value breaks the indentation. | indent(4) is the usual repair.

What this renderer does not do

No {% macro %}, {% include %}, {% raw %}, inline if expressions, or Ansible-only filters such as regex_replace and to_nice_yaml — those come from Ansible, not Jinja. Anything unsupported is reported in the warnings rather than dropped silently, so the output never looks more finished than it is.

Learn the theory