Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Environment variable interpolation

Substitute environment variables into route files and Camel.toml with ${env:VAR} tokens. The tokens work in endpoint URIs, log messages, header values, and any other string field.

The expansion point differs by surface. Route files expand in the raw route source, before YAML parsing. Camel.toml expands every string leaf of the parsed, merged tree. The tree combines the main file, include files, and CAMEL_* environment overrides. Expansion runs before typed deserialization.

Syntax

# =============================================================================
# env-interpolation example routes
#
# Uses ${env:VAR_NAME} to inject runtime environment variables.
# Supports default values with ${env:VAR_NAME:-default} syntax.
# Substitution happens before YAML parsing — works in URIs, messages, values.
#
# Try setting these before running:
#   GREET_TARGET=log:my-app
#   POLL_PERIOD_MS=2000
#   LOG_PREFIX="[demo]"
#
# If unset, defaults kick in automatically (see route 2).
# =============================================================================

routes:
  # ---------------------------------------------------------------------------
  # Route 1: env var in log message and endpoint URI
  # ---------------------------------------------------------------------------
  - id: "env-greet"
    from: "timer:env-tick?period=${env:POLL_PERIOD_MS}&repeatCount=3"
    steps:
      - log: "${env:LOG_PREFIX} Firing env-interpolation route"
      - set_header:
          key: "app"
          value: "${env:APP_NAME}"
      - to: "${env:GREET_TARGET}"

  # ---------------------------------------------------------------------------
  # Route 2: env var with default fallback syntax
  # ---------------------------------------------------------------------------
  - id: "env-defaults"
    from: "timer:env-defaults?period=${env:DEFAULT_POLL_MS:-3000}&repeatCount=2"
    steps:
      - log: "${env:DEFAULT_LOG_PREFIX:-[defaults]} Using fallback defaults"
      - to: "${env:DEFAULT_TARGET:-log:info}"

${env:VAR} reads the variable VAR. ${env:VAR:-default} uses default when VAR is unset. An unset variable with no default fails load. The error names the variable. Set a default or export the variable to avoid the failure.

The same syntax works in Camel.toml:

[security.keycloak]
client_secret = "${env:KC_SECRET}"

[observability.otel]
endpoint = "${env:OTEL_ENDPOINT:-http://localhost:4317}"

Escapes

InputOutput
${env:VAR}Value of VAR; fails closed if unset and no default
${env:VAR:-default}Value of VAR, or default when unset
$$A single $
$${env:VAR}The literal text ${env:VAR}

The standalone $$ escape works on every surface: route files and all Camel.toml leaves. The full-form escape $${env:VAR} yields the literal placeholder text on route files and plain Camel.toml leaves.

Exception — credential leaves: Camel.toml sections that hold credentials or connection secrets reject the escaped full form. On security, datasources, idempotent_repo, and cache_repo leaves, a $${env:VAR} leaves a residual ${env:VAR} marker, which fails load. There is no legitimate reason for a credential field to hold the literal text of a placeholder.

Fail-closed

Both surfaces fail closed. An unset variable without a default aborts:

  • Route discovery fails with an error naming the variable.
  • Camel.toml load aborts with an error naming the field.

Use ${env:VAR:-default} for optional values.

Legacy {{...}} syntax

Camel.toml rejects the legacy {{...}} placeholder syntax. Any {{ in a string leaf fails load with an actionable message: placeholders use ${env:NAME} or ${env:NAME:-default}. Route files never supported the {{...}} form.

How it works

The DSL loader (camel_dsl::interpolate_env) scans raw route source before YAML parsing. camel-config walks the merged Camel.toml tree after the builder merges the main file, include files, and CAMEL_* environment overrides (resolve_tree_placeholders). The walk replaces ${env:...} patterns before typed deserialization. Substituted values pass through sanitize_env_value, which strips control characters and newlines. This blocks newline injection from a hostile or malformed variable.

The PropertiesResolver type in camel-config retains the legacy {{...}} API for compatibility. Camel.toml loading does not use it.

Setup

    let config =
        CamelConfig::from_file("Camel.toml").map_err(|e| CamelError::Config(e.to_string()))?;

    let mut ctx = CamelContext::builder().build().await.unwrap(); // allow-unwrap
    ctx.register_component(TimerComponent::new());
    ctx.register_component(LogComponent::new());

    let routes = discover_routes(&config.routes).map_err(|e| CamelError::Config(e.to_string()))?;

The Camel.toml for this example is minimal. Route discovery and component registration follow the standard pattern.

[default]
routes = ["routes/**/*.yaml"]
log_level = "INFO"

When to use

  • Twelve-factor apps: inject configuration that varies per deploy through the environment, not through files in source control.
  • Secrets: pass credentials and tokens from the environment. The route file never stores the secret value.
  • Per-environment endpoints: point routes at different brokers, HTTP hosts, or databases without editing route files.

Reference: PropertiesResolver in the Config crate