Write a Jinja2 Transformation
A Jinja2 Transformation renders Infrahub data through a Jinja template, producing plain text output (configurations, manifests, payloads). The steps below cover how to write one.
For conceptual background, see Transformations. For a step-by-step walkthrough with a running example, see Build a Jinja2 Transformation in the Academy tutorials.
Assumes a working Infrahub instance, a connected Git repository, and
infrahubctlconfigured locally. See Installation and Connect a repository if you're starting fresh.
Write the GraphQL query​
Create a .gql file with the data you need to render in the Git repository. Use variables for per-target scoping.
query MyQuery($device_name: String!) {
InfraDevice(name__value: $device_name) {
edges {
node {
name { value }
# ... other fields
}
}
}
}
For reusable query fragments shared across Transformations or Generators, see GraphQL fragments.
Write the Jinja template​
Create a .j2 template under templates/ (or wherever fits your repository structure). The GraphQL query result is available as data in the template context.
{% set device = data.InfraDevice.edges[0].node %}
hostname {{ device.name.value }}
{# ... your config rendering logic #}
The template can include other templates with {% include %}. See the SDK Templating Reference for the full filter set.
Register in .infrahub.yml​
Add the Transformation definition to your repository's .infrahub.yml:
jinja2_transforms:
- name: <your_transform>
description: "<one-line description>"
query: <your_query>
template_path: "templates/<your_template>.j2"
queries:
- name: <your_query>
file_path: "queries/<your_query>.gql"
For full .infrahub.yml syntax, see infrahub.yml configuration.
Test locally​
Render the Transformation against your data:
infrahubctl render <your_transform> <var_name>=<value>
Use --branch=<branch_name> to render against a specific branch. Output prints to the terminal. Add --debug to surface the rendered query and intermediate state.
Deploy to Infrahub​
Commit your changes to the repository and push them up to your remote. The Transformation registers with Infrahub when the repository syncs.
Render via the API​
Once deployed, render on demand:
GET https://<host>/api/transform/jinja2/<your_transform>?branch=<branch_name>&<var>=<value>
The endpoint is branch-aware. Pass query variables as URL parameters.
Generate as an artifact​
To cache rendered output and tie it to a specific target object, define an artifact that uses this Transformation. See Use artifacts.
Dependency tracking​
When a Jinja2 Transformation feeds an artifact, Infrahub regenerates that artifact only when a file the template depends on changes. On import, Infrahub walks the template and records every other template it reaches through static {% include %}, {% import %}, and {% extends %} directives, following them transitively. A change to any template in that set regenerates the artifacts of definitions that use this Transformation.
Static directives resolve automatically. A dynamic reference — where the template name comes from a variable, as in {% include partial_name %} — can't be followed at import time. Infrahub then marks the Transformation's dependency closure incomplete and falls back to regenerating its artifacts on any file change in the repository. To keep regeneration precise, either:
- Replace the variable with a literal name, for example
{% include "partials/header.j2" %}, or - Declare the templates the dynamic reference can resolve to with the
watchkey in.infrahub.yml.
See Understanding artifact regeneration for how to read which change triggered a regeneration.
Related​
- Transformations — concept and architecture
- Write a Python transformation — for non-template logic
- GraphQL fragments — share query fragments across Transformations
- Use artifacts — cache Transformation output
- infrahub.yml configuration