Crates.io | tenvy |
lib.rs | tenvy |
version | 1.0.0 |
created_at | 2025-09-22 12:14:50.829629+00 |
updated_at | 2025-09-22 12:14:50.829629+00 |
description | Parse environment variables into type-safe structures |
homepage | |
repository | https://gitlab.com/SnejUgal/tenvy |
max_upload_size | |
id | 1849962 |
size | 36,641 |
tenvy
Parse environment variables into type-safe structures.
use tenvy::Tenvy;
#[derive(Debug, Tenvy)]
struct Environment {
database_url: String,
server: Server,
}
#[derive(Debug, Tenvy)]
struct Server {
addr: std::net::SocketAddr,
workers: Option<std::num::NonZeroUsize>,
}
fn main() -> anyhow::Result<()> {
let env: Environment = tenvy::from_env()?;
println!("{env:#?}");
Ok(())
}
envy
and serde-env
?Both envy
and serde-env
make use of serde
to extract environment
variables into types. Although the idea to use serde
is rather nice and allows
to reuse features from serde
, it faces several challenges in practice:
Nested structures: envy
does not support them at all, while serde-env
provides suboptimal error messages if a variable is
missing;
Flattening: #[serde(flatten)]
is hard to support
because it uses deserialize_any
;
Renaming: counterintuitively you have to use lowercase names in
#[serde(rename)]
, and that also means you cannot differentiate between
lowercase-named and uppercase-named variables;
Customized deserialization: shall you need parse variables in a way that
cannot be achieved using serde_derive
, you have to resort to very
verbose Deserialize
implementation.
Genericity: empty substructures are not handled well. For example,
deserializing Environment<SubsystemStub>
successfully requires some variable
that starts with SUBSYSTEMS
to be present, although its value is never used:
#[derive(Deserialize)]
struct Environment<Subsystem> {
subsystem: Subsystem,
}
#[derive(Deserialize)]
struct SubsystemStub {}
Many of such issues arise because serde
is designed to parse various kinds of
data by giving everything it reads to the deserializer. However, when parsing
environment variables, we usually want to ask for data we need instead.
Moreover, we know that environment variables is a key-value structure with
basically random access.
So tenvy
takes this other approach when we know that we're dealing with a
key-value map and ask it for data we need. This approach should allow for much
more pleasant API with less obstacles and surprises.