Interpolation¶
As your configuration grows, you'll find yourself repeating the same values in multiple places. You might define a hostname once and then need to use it in several URLs. Or you might want to build connection strings from smaller pieces. Repeating these values makes your configuration harder to maintain and error-prone.
Interpolation solves this by letting you reference values within your configuration using a simple syntax: ${...}. Let's explore how it works.
Self-References: Keeping Configuration DRY¶
The most common use of interpolation is referencing other values in the same configuration file. This keeps your configuration DRY (Don't Repeat Yourself):
When you access server.url, HoloConf automatically resolves the references:
Now when you need to change the hostname, you only update it in one place.
Absolute References (Default)¶
By default, references are absolute - they specify the full path from the root of the configuration:
database:
host: db.example.com
port: 5432
app:
connection: postgres://${database.host}:${database.port}/mydb
Relative References¶
You can also use relative references with a dot prefix. This is especially useful for keeping configuration sections self-contained:
The dot syntax works like filesystem paths:
.sibling- Reference a sibling at the current level..parent- Go up one level (parent)...grandparent- Go up two levels (grandparent)- And so on...
Here's a more complex example showing how relative references make sections more modular:
company:
name: Example Corp
domain: example.com
engineering:
email_domain: ${..domain} # Parent: company.domain
backend:
team_name: ${...name} Backend Team # Grandparent: company.name
contact: backend@${..email_domain} # Parent: engineering.email_domain
When accessed:
When to Use Relative vs Absolute
Use absolute references when you need a specific value regardless of where you are in the config. Use relative references when you want to keep sections self-contained and easier to refactor.
Resolvers: Getting Values from External Sources¶
Self-references are powerful, but sometimes you need values from outside your configuration file - like environment variables, files, external services, or cloud provider APIs. This is where resolvers come in.
A resolver is a mechanism for fetching values from external sources. The syntax extends what you've already learned:
For example, to pull a value from an environment variable:
database:
host: ${env:DB_HOST}
port: ${env:DB_PORT}
url: postgres://${.host}:${.port}/db # Combines env values with self-reference
HoloConf includes several built-in resolvers for common use cases:
env- Environment variablesfile- File contentshttp/https- Remote content via HTTPssm- AWS Systems Manager Parameter Store (via plugin)cfn- CloudFormation stack outputs (via plugin)
You can even write your own custom resolvers in Python!
For detailed information on all available resolvers, their specific features, and advanced capabilities like defaults and sensitive value handling, see the Resolvers section.
Escaping Literal Dollars¶
What if you actually need a literal ${ in your configuration (like documenting the syntax)? Escape it with a backslash:
documentation:
example: "Use \${env:VAR_NAME} to reference environment variables"
template: "Hello \${name}, welcome to \${app}!"
The backslash tells HoloConf not to interpret this as interpolation:
Quick Reference¶
| Syntax | Description | Example |
|---|---|---|
${path.to.value} |
Self-reference (absolute) | ${database.host} |
${.sibling} |
Self-reference (current level) | ${.port} |
${..parent} |
Self-reference (parent level) | ${..shared.timeout} |
${...grandparent} |
Self-reference (grandparent level) | ${...company.name} |
${resolver:arg} |
External value via resolver | ${env:DB_HOST} |
\${literal} |
Escape interpolation | \${not_interpolated} |
What You've Learned¶
You now understand:
- Interpolation basics - Using
${...}to avoid repeating values - Self-references - Referencing other config values (absolute and relative)
- Relative references - Using
.,..,...to navigate the config tree - Resolvers - Fetching values from external sources like environment variables
- Escaping - Using
\${for literal dollar signs
Next Steps¶
- Resolvers - Deep dive into all available resolvers, defaults, sensitive values, and custom resolvers
- Merging - Combine multiple configuration files with layered overrides
- Validation - Catch configuration errors early with JSON Schema
See Also¶
- ADR-011 Interpolation Syntax - Technical details and design rationale