Files
envkit/README.md
T
2026-06-08 12:38:41 -04:00

3.6 KiB

envkit

envkit is a small Rust crate for reading environment variables as typed values.

It provides a minimal loader API for required values, optional values, defaults, prefixed variable names, and simple .env-style files.

Install

Add envkit to your Cargo.toml:

[dependencies]
envkit = "0.2.1"

Quick Start

use envkit::EnvLoader;

fn main() -> Result<(), envkit::error::EnvError> {
    let env = EnvLoader::new();

    let port: u16 = env.get("PORT")?;
    let debug: bool = env.get_or("DEBUG", false);
    let app_name: String = env
        .get_opt("APP_NAME")
        .unwrap_or_else(|| "envkit".to_string());

    println!("{app_name} listening on port {port}; debug={debug}");
    Ok(())
}

API

EnvLoader::get

Reads a required environment variable and parses it into the requested type.

let env = envkit::EnvLoader::new();
let port: u16 = env.get("PORT")?;

Returns EnvError::MissingVar when the variable is not set and EnvError::Invalid when parsing fails.

EnvLoader::get_or

Reads an environment variable and returns a fallback when the variable is missing or invalid.

let debug: bool = env.get_or("DEBUG", false);

EnvLoader::get_opt

Reads an environment variable and returns None when the variable is missing or invalid.

let name: Option<String> = env.get_opt("APP_NAME");

EnvLoader::with_prefix

Creates a loader that prepends a prefix to every key.

let app = env.with_prefix("APP_");

let host: String = app.get("HOST")?; // reads APP_HOST
let port: u16 = app.get_or("PORT", 8080); // reads APP_PORT

EnvLoader::load_file

Loads variables from a file with one KEY=VALUE pair per line.

let env = envkit::EnvLoader::new();
env.load_file(".env")?;

Blank lines and lines starting with # are ignored. Keys and values are trimmed before being written into the process environment.

Example file:

# .env
PORT=8080
DEBUG=true
APP_NAME=envkit

Supported Types

Built-in parsing supports:

  • String
  • bool
  • signed integers: i8, i16, i32, i64, i128, isize
  • unsigned integers: u8, u16, u32, u64, u128, usize
  • floats: f32, f64
  • Vec<T> where T also implements FromEnv

Boolean values accept:

  • true / false
  • 1 / 0
  • t / f
  • yes / no

Lists are comma-separated and each item is trimmed before parsing:

let env = envkit::EnvLoader::new();
let ports: Vec<u16> = env.get("PORTS")?;
let flags: Vec<bool> = env.get("FEATURE_FLAGS")?;

Custom Types

Implement FromEnv for your own types when you want domain-specific parsing.

use envkit::{error::EnvError, FromEnv};

enum LogFormat {
    Json,
    Pretty,
}

impl FromEnv for LogFormat {
    fn from_env(value: &str) -> Result<Self, EnvError> {
        match value.trim().to_lowercase().as_str() {
            "json" => Ok(Self::Json),
            "pretty" => Ok(Self::Pretty),
            other => Err(EnvError::invalid(
                "LogFormat",
                other,
                "expected `json` or `pretty`",
            )),
        }
    }
}

Errors

envkit returns EnvError values:

  • EnvError::MissingVar(key) when a required environment variable is not set.
  • EnvError::Invalid { key, value, message } when a value cannot be parsed.
  • EnvError::FileError { path, message } when a file cannot be read or contains an invalid line.

Examples

Run the included examples with:

cargo run --example basic
cargo run --example prefixed

The examples seed their own environment variables so they can be run directly.

Development

Run the test suite with:

cargo test