Controlling whitespace in Jinja2 templates

From Freephile Wiki
Revision as of 22:55, 22 July 2025 by Admin (talk | contribs) (use spaces)

For background perspective, Jinja is used as a templating system by various Python projects like Django, Flask, or Ansible.

Use spaces[edit]

Since Jinja is based on Python where spaces are relevant, it is preferred to use spaces in your templates rather than tabs.

From the Jinja2 documentation, there are two options to control whitespace in Jinja templates:

  • trim_blocks
  • lstrip_blocks

But actually, there's more to it. The "Template Designer Documentation" specifically for whitespace control is inadequate. That's why I wrote this article.

Jinja in Ansible[edit]

In Ansible's Template module, you can see in the source code

But what does this mean? What do these options do? And how do I use them in my Ansible templates?

trim blocks means the first newline after a block is removed (block, not variable tag!)

lstrip blocks [1] means leading spaces and tabs are stripped from the start of a line to a block.

So, I can read words, but without context nor further example and explanation, I can't decode what "from the start of a line to a block" means.


In the task[edit]

In at least v2.9 of Ansible, the Template module has options to specify both.

[meza-ansible@rockylinux-s-4vcpu-8gb-nyc3-01 config]$ ansible --version
ansible [core 2.16.3]
  config file = /opt/meza/config/ansible.cfg
  configured module search path = ['/opt/conf-meza/users/meza-ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.12/site-packages/ansible
  ansible collection location = /opt/meza/collections
  executable location = /usr/bin/ansible
  python version = 3.12.11 (main, Jul  1 2025, 15:29:55) [GCC 8.5.0 20210514 (Red Hat 8.5.0-26)] (/usr/bin/python3.12)
  jinja version = 3.1.2
  libyaml = True
# Adds extensions with composer param from MezaCoreExtensions.yml,
# MezaLocalExtensions.yml, MezaCoreSkins.yml, and MezaLocalSkins.yml
- name: Ensure composer.local.json in place to load composer-based extensions
  template:
    src: composer.local.json.j2
    dest: "{{ m_mediawiki }}/composer.local.json"
    mode: "{{ m_htdocs_mode }}"
    owner: "{{ m_htdocs_owner }}"
    group: "{{ m_htdocs_group }}"
    lstrip_blocks: false
    trim_blocks: true

In the template file[edit]

As the very first line of your template file, you can use a magic comment directive to control the behavior of the Ansible Template module #jinja2: trim_blocks: "true", lstrip_blocks: "true"[2]

By hand[edit]

I was so frustrated by the lack of clear examples that showed all variants, I created a project on GitHub called test-jinja that does exactly that. TLDR. [3]

You could also use the jinja2 live parser project to interactively preview jinja. I found Ansible playbook execution to be inconsistent with the expected behavior and results I was getting from the live parser. But at least it gives you the ability to run through example template loops, conditions and blocks interactively to illustrate how the Ansible playbook should work. The short version of using the live parser is to clone the repo, build it, and docker run it.

# clone it
git clone https://github.com/abourguignon/jinja2-live-parser.git
# change into the cloned source directory
cd jinja2-live-parser/
# build and tag the image
docker build -t mydocker/j2parser .
# run it on port 5000 in detached mode
docker run -d -p 5000:5000 mydocker/j2parser

Or, just pull and run the pre-built image from Docker hub.

Variables[edit]

If you're confused about Variable notation and how those are defined in templates, see https://jinja.palletsprojects.com/en/3.1.x/templates/#variables

Debugging[edit]

Just put {% debug %} somewhere in your template file. This didn't work for me in Ansible 2.9

More[edit]

Bloomreach Engagement is a commercial Web product that uses Jinja for templating. So they have a pretty good reference guide.

See Also[edit]

For whitespace formatting of YAML block scalars, see the yamllint article.

References[edit]

  1. lstrip stands for "left strip". It is a function in Python, as well as R and Ruby. Like ltrim in PHP or trimStart in JavaScript. nb. Jinja also has a built-in filter named trim that is used to strip characters from the beginning and end of a string.
  2. It's unclear whether the boolean value(s) to be quoted. I believe it was a bug that is now fixed - meaning they can be bare.
  3. Inspiration from https://github.com/ansible/ansible/pull/37478