How to Use Environment Variables in Jinja2 Templates

TL;DR

Register os.getenv as a global in the Jinja2 environment so any template — whether from jinja_render, jinja_render_convert, or a custom fetch module — can resolve environment variables inline with {{ getenv('VAR', 'default') }}. No imports, no extra .render() arguments.

When to use this

  • You have an API base URL that varies per environment and don’t want to hardcode it in the template

  • You need to inject a tenant-specific value from the environment into a generated field (e.g., an issuer URL, a region code)

  • You want to keep a single config.yaml across dev/staging/prod and resolve differences from the environment

Prerequisites

  • oaa-runner version that includes jinja_env.globals['getenv'] = os.getenv (post-2026-07-06)

  • Environment variables set before running oaa app run

How it works

One line in src/oaa/utils.py:

jinja_env.globals['getenv'] = os.getenv

This makes os.getenv callable as getenv(...) inside any Jinja2 template rendered by the oaa-runner framework. The second argument to getenv is the fallback default — if the variable is not set, that string is used instead.

Basic usage

In a field mapping, reference environment variables directly in the template:

transforms:
  - name: jinja_render
    options:
      template: "{{ getenv('ISSUER_URL', 'https://default.issuer.com') }}/api/v2/users/{{ row.id }}"

If ISSUER_URL is set in the environment → uses that. If not → falls back to https://default.issuer.com.

Using with jinja_render_convert

transforms:
  - name: jinja_render_convert
    options:
      template: "{{ getenv('REGION', 'us-east-1') }}:{{ value }}"

Combining with required_env

For a hard requirement (fail the run if the var is missing), list it in required_env on the connection. For a soft default (use a fallback if unset), use getenv('VAR', 'default') in the template.

connections:
  my_api:
    connection_type: api
    required_env:
      - API_KEY         # hard requirement — fails early if missing
    params:
      base_url: "{{ getenv('BASE_URL') }}"  # soft — resolves at render time

In custom fetch modules

If you are calling simple_jinja_render from a Python module:

from oaa.utils import simple_jinja_render

path = simple_jinja_render("/api/{{ getenv('TENANT') }}/users")

Security

  • getenv is resolved at render time — values are not stored in config.yaml or serialized to disk

  • The fallback default is the string literal in the template — it is visible in config.yaml

  • For sensitive values, prefer required_env validation + connection.params injection, and only use getenv in templates for non-secret configuration like URLs, regions, or log levels

See also