0 / 13 lessons — 0%
Lesson 06 / 13

Jinja2 templates

The copy module ships a static file as-is. The template module ships a file with Jinja2 placeholders inside, filled in per-host at deploy time — one template, many rendered outputs.

# templates/nginx.conf.j2 server { listen {{ nginx_port }}; server_name {{ inventory_hostname }}; location / { proxy_pass http://127.0.0.1:{{ app_port }}; } {% if enable_ssl %} ssl_certificate /etc/ssl/certs/{{ inventory_hostname }}.crt; ssl_certificate_key /etc/ssl/private/{{ inventory_hostname }}.key; {% endif %} }
- name: Deploy nginx config from template template: src: templates/nginx.conf.j2 dest: /etc/nginx/sites-available/app.conf vars: nginx_port: 80 app_port: 3000 enable_ssl: false notify: Restart nginx

{{ }} substitutes a value; {% %} runs logic — conditionals, loops — that doesn't itself appear in the output. Any variable in scope (inventory, group_vars, facts, playbook vars) is usable inside a template.

Same idea as Docker Compose's env vars or Helm's values.yaml, one more time. Every infrastructure tool in this track eventually reinvents "one template, filled in differently per target" — recognizing the pattern makes each new tool faster to pick up.
Try it yourselfWrite a tiny template with one {{ variable }} in it, deploy it to a test host with the template module, then look at the rendered file on that host. The placeholder is gone — replaced with the real value.