Rust
To use varlock with Rust, install the standalone binary and run your app under varlock run — it loads and validates your env, then injects it into the process.
Add @generateRustEnv to your schema to generate a small, self-contained module — a serde-derived Env struct, a load() function that parses the injected __VARLOCK_ENV blob, and a SENSITIVE_KEYS constant.
# @generateRustEnv(path=src/env.rs)The file is regenerated automatically on varlock load and varlock run, or explicitly with varlock codegen. It needs serde and serde_json:
cargo add serde --features derivecargo add serde_jsonReading values
Section titled “Reading values”Call load() once, then read fields off the struct — required fields are the plain type, optional ones are Option<T>:
mod env;
fn main() -> Result<(), Box<dyn std::error::Error>> { let e = env::load()?; // call once, hold or pass `e` around let host = e.db_host; // String (required field) if let Some(port) = e.db_port { // Option<i64> (optional field) println!("{host}:{port}"); } Ok(())}varlock run -- cargo runload() returns a clear error if __VARLOCK_ENV is missing (e.g. you forgot varlock run) or if a required key is absent. The struct derives a redacting Debug — sensitive fields print as <redacted>, so {:?} won’t leak secrets.
Sharing one instance
Section titled “Sharing one instance”Every load() call re-parses the blob. If you want a process-wide instance, opt into a LazyLock yourself (loaded once, on first access; LazyLock needs Rust 1.80+, or use once_cell::sync::Lazy on older toolchains):
use std::sync::LazyLock;use crate::env;
pub static ENV: LazyLock<env::Env> = LazyLock::new(|| env::load().expect("failed to load env"));use crate::config::ENV;
let port = ENV.db_port; // Option<i64>Prefer no globals? Call env::load()? once in main and pass &Env through your app state — the type comes along either way.