Ridha Tech
Get Started
← Back to Blog
Technical Deep Dive

Building Valo: Jinja2 Config Loading — When YAML Needs Superpowers

June 8, 20266 min read

Environment variables hardcoded in YAML files? That's a maintenance nightmare waiting to happen.

Today we implemented Valo's configuration loader using Jinja2 templating — the exact pattern Anthropic's Sentinel uses for production AI workflows.

The Problem: Static YAML Isn't Enough

Standard YAML configs force you into multiple files (config-dev.yml, config-staging.yml, config-production.yml), each duplicating structure and differing only in values.

Any structural change means updating all three. Miss one? Production breaks.

The Solution: Template First, Parse Second

Jinja2 + YAML gives you dynamic configuration with static structure. One file, multiple environments, no duplication:

aws:
  region: ${ AWS_REGION }
  account: ${ AWS_ACCOUNT }
database:
  host: ${ DB_HOST }
  port: 5432

Implementation: TDD All The Way

We wrote 14 tests before a single line of implementation. The loading flow:

  1. Read YAML file as text
  2. Process with Jinja2 (variable substitution)
  3. Parse rendered text as YAML
  4. Return Python dict

The YAML Quirk

Unquoted empty values in YAML become null. To preserve empty strings, use quotes:

# This becomes null
optional: ${ MISSING_VAR }

# This becomes ""
optional: "${ MISSING_VAR }"

We updated our tests to reflect actual YAML behavior rather than fighting the spec.

Quality Metrics

  • 52 tests passing (14 new config tests + 38 previous)
  • 93% overall coverage (config loader: 85%)
  • Zero mypy errors (strict mode)
  • Zero ruff errors

Testing first. Quality always. No compromises.