| 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 |
tenvyParse 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.