How TOML Configuration Is Loaded at Server Startup Using Environment Variables in Switchyard

Switchyard loads TOML configuration by reading a filesystem path, deserializing it into ServerConfig, then resolving *_env fields by looking up the named environment variables and injecting their values into the runtime server state.

This pattern lets operators store sensitive credentials like API keys outside of version-controlled configuration files. The implementation lives primarily in the Rust server crate, with Python CLI helpers passing the configuration path through environment variables.

Overview of the Configuration Loading Flow

The Switchyard server follows a four-stage initialization process when it boots:

  1. Path resolution – The server obtains a TOML file path, typically from the SWITCHYARD_CONFIG environment variable
  2. File reading – Raw bytes are read from disk using standard Rust filesystem APIs
  3. TOML deserialization – toml::from_str parses the file into the ServerConfig struct
  4. Environment variable injection – Fields ending in _env trigger lookups via std::env::var, with results merged into the final configuration

This architecture separates structural configuration (routes, limits, timeouts) from secret material (API keys, authentication tokens), addressing a common operational security requirement for LLM gateway deployments.

Key Source Files and Their Roles

File Purpose Direct Source Link
crates/switchyard-server/src/config.rs Core configuration types, TOML parsing, and *_env resolution logic config.rs on GitHub
crates/switchyard-server/src/lib.rs Server initialization and load_server_state export lib.rs on GitHub
switchyard/cli/launch_command.py Python CLI that sets SWITCHYARD_CONFIG and invokes the Rust binary launch_command.py on GitHub
dev-server/config.toml Reference configuration demonstrating environment variable patterns config.toml on GitHub

Implementation Details in config.rs

The ServerConfig struct in crates/switchyard-server/src/config.rs defines the schema for TOML configuration. Critical to environment variable support are fields like api_key_env and base_url_env, which store the name of an environment variable rather than its value.

After deserialization completes, the configuration loader iterates over these *_env fields:

  • Calls std::env::var(env_var_name) for each configured variable name
  • Returns a descriptive error if the variable is unset or contains only whitespace
  • Substitutes the retrieved value into the corresponding operational field (e.g., api_key for LLM client authentication)

This two-step process ensures that TOML files can be committed to repositories safely, while still permitting per-deployment customization of secrets and endpoint URLs.

Running the Server with Environment-Driven Configuration

Shell Example


# Point Switchyard to your TOML configuration file

export SWITCHYARD_CONFIG=/etc/switchyard/production.toml

# Provide secrets that the TOML file references by variable name

export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...

# Launch the server (CLI passes SWITCHYARD_CONFIG to the Rust binary)

switchyard launch

Minimal TOML Snippet with Environment References

[llm_clients.openai_gpt4]
base_url = "https://api.openai.com/v1"
api_key_env = "OPENAI_API_KEY"  # Value pulled from environment at startup

[llm_clients.anthropic_claude]
base_url = "https://api.anthropic.com/v1/complete"
api_key_env = "ANTHROPIC_API_KEY"

Verifying Configuration Resolution Programmatically

For debugging or integration testing, you can inspect the resolved configuration from Python:

from switchyard_rust.server import load_server_state
import os

# Mimic the environment setup that the CLI performs

os.environ["SWITCHYARD_CONFIG"] = "dev-server/config.toml"
os.environ["OPENAI_API_KEY"] = "sk-test-key-12345"

# Load and validate the full server state

state = load_server_state(os.getenv("SWITCHYARD_CONFIG"))

# The API key has been resolved from the environment and is now populated

print(state.llm_clients["openai_gpt4"].api_key)  # outputs: sk-test-key-12345

print(state.routes)                               # shows fully configured routing table

This pattern is particularly useful in test suites that need to verify configuration parsing without spawning a full HTTP server.

Error Handling for Missing Variables

The Switchyard implementation is strict about environment variable presence. If a TOML file declares api_key_env = "REQUIRED_SECRET" but REQUIRED_SECRET is unset at runtime, load_server_state fails fast with an error message identifying:

  • The configuration file path
  • The field requiring the variable
  • The exact environment variable name that was not found

This fail-fast behavior prevents silent misconfigurations that would otherwise manifest as authentication failures downstream.

Summary

  • TOML configuration in Switchyard is loaded via load_server_state in crates/switchyard-server/src/config.rs
  • Environment variables are referenced by name in *_env fields and resolved after TOML parsing completes
  • Secrets stay out of files – only variable names are stored in TOML, with values injected at runtime from std::env::var
  • CLI integration – The switchyard launch command sets SWITCHYARD_CONFIG before invoking the Rust server binary
  • Strict validation – Missing environment variables produce immediate, descriptive errors rather than silent defaults

Frequently Asked Questions

What environment variable specifies the TOML configuration file path?

Switchyard uses SWITCHYARD_CONFIG as the conventional environment variable for the configuration file path. The Python launch command sets this automatically when you invoke switchyard launch, or you can set it manually to override the default location.

Can I use environment variables for values other than API keys?

Yes. The *_env pattern applies to multiple configuration fields. In addition to api_key_env, the Switchyard schema supports base_url_env and potentially other environment-referenced fields defined in ServerConfig. Any value that varies across deployments—endpoints, timeout values, feature flags—can be externalized using this mechanism.

What happens if an environment variable referenced in my TOML file is missing?

The server fails during startup with a clear error message. The load_server_state implementation validates that every *_env field resolves to a non-empty string, returning an error that identifies the missing variable by name. This prevents the server from starting in a partially configured state.

Is there a way to inspect the resolved configuration without starting the HTTP server?

Yes. Import load_server_state from switchyard_rust.server in Python, set your environment variables and SWITCHYARD_CONFIG path, then call the function directly. This returns a populated ServerState object containing all resolved values without binding to any network ports.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →