# Tip: Jinja2 Macros

**URL:** <https://cylc.discourse.group/t/tip-jinja2-macros/1321>\
**Category:** Tips\
**Created:** [May 24, 2026, 10:18pm UTC](https://cylc.discourse.group/t/tip-jinja2-macros/1321 "2026-05-24T22:18:35Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![hilary.j.oliver](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/hilary.j.oliver/32/4_2.png) [@hilary.j.oliver](https://cylc.discourse.group/u/hilary.j.oliver)\
**Post date:** [May 24, 2026, 10:18pm UTC](https://cylc.discourse.group/t/tip-jinja2-macros/1321/1 "2026-05-24T22:18:35Z")

</div>

Jinja2 macros are great way to automatically construct parts of your workflow based on input parameters (macro arguments).

Here’s an example macro that adds a task to print a given word (default “hello”) to stdout, after a given task in your graph:

```ini
{% macro say_it(
        after_task,
        say_what = "hello"
    )
%}
[scheduling]
    [[graph]]
        R1 = "{{after_task}} => say_{{say_what}}"
[runtime]
    [[say_{{say_what}}]]
        script = "echo {{say_what}}"
{% endmacro %}

```

And a workflow that uses it twice:

```ini
#!Jinja2
{% import 'macros.j2' as macros %}

{{ macros.say_it(after_task="b")}}
{{ macros.say_it(after_task="c", say_what="goodbye")}}
[scheduling]
    [[graph]]
        R1 = "a => b => c"
[runtime]
    [[a, b, c]]

```

Here’s the result after template processing and config parsing, via `cylc config`:

```ini
[scheduling]
    initial cycle point = 1
    final cycle point = 1
    cycling mode = integer
    [[graph]]
        R1 = """
            b => say_hello
            c => say_goodbye
            a => b => c
        """
[runtime]
    [[root]]
    [[say_hello]]
        script = echo hello
        completion = succeeded
    [[say_goodbye]]
        script = echo goodbye
        completion = succeeded
    [[a]]
        completion = succeeded
    [[b]]
        completion = succeeded
    [[c]]
        completion = succeeded

```
