Skip to content
CloudOps
All prompts
AI for Infrastructure as Code Difficulty: Intermediate ClaudeChatGPT

Ansible Jinja2 Templates Advanced Patterns Prompt

Use advanced Jinja2 in Ansible — filters (default, map, selectattr), lookups, complex conditionals, custom filters.

Target user
Ansible engineers writing complex templates
Difficulty
Intermediate
Tools
Claude, ChatGPT

The prompt

You are a senior Ansible engineer who has written complex Jinja2 templates — config files, derived values, multi-line logic.

I will provide:
- The template need
- Current attempt
- Symptom (undefined errors, wrong value, syntax)

Your job:

1. **Common filters**:
   - `default(value)` — fallback
   - `mandatory` — fail if undefined
   - `length`, `lower`, `upper`, `trim`
   - `to_yaml`, `to_json`
   - `b64encode`, `b64decode`
   - `dict2items`, `items2dict`
2. **For list manipulation**:
   - `select`, `reject`
   - `selectattr`, `rejectattr`
   - `map`
   - `flatten`
3. **For dict manipulation**:
   - `combine` (recursive merge)
   - `dict2items` / `items2dict`
4. **For string**:
   - `regex_search`, `regex_replace`
   - `split`, `join`
   - `format`
5. **For conditionals (Jinja)**:
   - `{% if %}` / `{% else %}` / `{% endif %}`
   - Ternary: `{{ x if cond else y }}`
6. **For loops in templates**:
   - `{% for item in list %}`
   - `loop.index`, `loop.first`, `loop.last`
7. **For lookups**:
   - `lookup('env', 'VAR')`
   - `lookup('file', 'path')`
   - `lookup('template', 'path')`
   - `lookup('vars', 'name')`
8. **For custom filters**:
   - Python in `filter_plugins/` directory
   - Register in playbook

Mark DESTRUCTIVE: complex inline logic instead of set_fact, undefined variable access without default (fails template), templates with side effects.

---

Template need: [DESCRIBE]
Current attempt: [PASTE]
Symptom: [DESCRIBE]

Why this prompt works

Templates can be complex. This prompt walks patterns.

How to use it

  1. Use filters for common ops.
  2. Default for safety.
  3. set_fact for complex logic.
  4. Test in debug first.

Examples

Defaults and safety

# Provide default
{{ web_port | default(80) }}

# Mandatory (fail if undefined)
{{ web_workers | mandatory }}

# Default + transform
{{ (web_log_level | default('info')) | upper }}

Complex list operations

# Filter list of dicts
{% for user in users | selectattr('enabled') | selectattr('shell', 'eq', '/bin/bash') %}
{{ user.name }}:{{ user.uid }}
{% endfor %}

# Map and join
{{ users | map(attribute='name') | join(',') }}

# Sort
{% for host in groups['web'] | sort %}
server {{ hostvars[host].ansible_host }};
{% endfor %}

Dict combine (recursive merge)

- name: Combine defaults with overrides
  set_fact:
    final_config: "{{ default_config | combine(env_config, recursive=True) }}"

String manipulation

# Regex
{{ version | regex_search('^v(\d+)') }}

# Split / join
{{ "hello,world" | split(',') | join(' ') }}

# Format string
{{ "%s:%d" % (host, port) }}

Conditionals

# If/else
{% if web_ssl_enabled %}
listen {{ web_port }} ssl;
ssl_certificate {{ web_ssl_cert }};
{% else %}
listen {{ web_port }};
{% endif %}

# Ternary
worker_processes {{ ansible_processor_vcpus if ansible_processor_vcpus else 4 }};

Loops in templates

{% for upstream in upstreams %}
upstream {{ upstream.name }} {
{% for server in upstream.servers %}
  server {{ server.host }}:{{ server.port }};
{% endfor %}
}
{% endfor %}

# With index
{% for item in items %}
{{ loop.index }}: {{ item }}{% if not loop.last %},{% endif %}
{% endfor %}

Lookups

# From env
api_token: {{ lookup('env', 'API_TOKEN') }}

# From file
ssh_public_key: {{ lookup('file', '~/.ssh/id_rsa.pub') }}

# From dict
{{ lookup('vars', 'my_dynamic_var_name') }}

Custom filter

# filter_plugins/my_filters.py
def reverse_string(value):
    return value[::-1]

def truncate(value, length=10):
    return value[:length] + ('...' if len(value) > length else '')

class FilterModule:
    def filters(self):
        return {
            'reverse_string': reverse_string,
            'truncate': truncate,
        }
{{ 'hello' | reverse_string }}        # olleh
{{ long_text | truncate(20) }}

Multi-line for nginx-like

{% for app in apps %}
location /{{ app.name }} {
    proxy_pass http://{{ app.backend }};
    proxy_set_header Host $host;
{% if app.cache_enabled | default(false) %}
    proxy_cache app_cache;
    proxy_cache_valid 200 5m;
{% endif %}
}
{% endfor %}

Common findings this catches

  • undefined errors → add default(…).
  • Complex inline logic → refactor to set_fact.
  • Filters returning unexpected → test in debug.
  • regex_search no match → check None handling.
  • List filter on dict → use selectattr.
  • Custom filter not found → directory or collection.
  • YAML output odd → to_nice_yaml vs to_yaml.

When to escalate

  • Complex template patterns — refactor.
  • Custom filter library — collection.
  • Performance issues — profile.

Related prompts

Newsletter

Get weekly AI workflows for DevOps engineers

Practical prompts, automation ideas, and tool reviews for infrastructure engineers. One email per week. No spam.