EnvLoader

Struct EnvLoader 

Source
pub struct EnvLoader { /* private fields */ }
Expand description

Loads environment files with automatic decryption of encrypted values.

EnvLoader reads .env files in a specific order and automatically decrypts any encrypted values it encounters. It supports multiple environment variants and user-specific configuration files.

§Examples

use dotenvage::EnvLoader;

// Load from current directory
EnvLoader::new()?.load()?;

// Now encrypted values are available via std::env::var
let api_key = std::env::var("API_KEY")?;

§File Loading Order

Files are loaded in the following order (later files override earlier ones):

  1. .env - Base configuration
  2. .env.<ENV> - Environment-specific
  3. .env.<ENV>-<ARCH> - Architecture-specific (if <ARCH> is set)
  4. .env.<USER> - User-specific overrides (if <USER> is set)
  5. .env.<ENV>.<USER> - User overrides for specific environment
  6. .env.<ENV>-<ARCH>.<USER> - User overrides for env+arch combo
  7. .env.pr-<PR_NUMBER> - PR-specific (GitHub Actions only)

Note: Separators can be either . or - (e.g., .env.local or .env-local)

§Placeholders

The following placeholders are resolved from environment variables:

Implementations§

Source§

impl EnvLoader

Source

pub fn new() -> SecretsResult<Self>

Creates a new EnvLoader with a default SecretManager.

This will load the encryption key from standard locations: 0. Auto-discover AGE_KEY_NAME from .env or .env.local files

  1. DOTENVAGE_AGE_KEY environment variable (full identity string)
  2. AGE_KEY environment variable
  3. Key file at path determined by discovered AGE_KEY_NAME
  4. Default key file at XDG path (e.g., ~/.local/state/dotenvage/dotenvage.key)
§Errors

Returns an error if no encryption key can be found or loaded.

Source

pub fn with_manager(manager: SecretManager) -> Self

Creates an EnvLoader with a specific SecretManager.

Use this when you want to provide your own encryption key.

§Examples
use dotenvage::{
    EnvLoader,
    SecretManager,
};

let manager = SecretManager::generate()?;
let loader = EnvLoader::with_manager(manager);
loader.load()?;
Source

pub fn load(&self) -> SecretsResult<()>

Loads .env files from the current directory in standard order.

Decrypted values are loaded into the process environment and can be accessed via std::env::var().

§Errors

Returns an error if any file cannot be read or parsed, or if decryption fails for any encrypted value.

§Examples
use dotenvage::EnvLoader;

EnvLoader::new()?.load()?;
let secret = std::env::var("API_TOKEN")?;
Source

pub fn load_from_dir(&self, dir: impl AsRef<Path>) -> SecretsResult<()>

Loads .env files from a specific directory using the same order as load.

§Errors

Returns an error if any file cannot be read or parsed, or if decryption fails for any encrypted value.

Source

pub fn resolve_env_paths(&self, dir: &Path) -> Vec<PathBuf>

Computes the ordered list of env file paths to load.

This method uses a power-set generation approach: it resolves ENV, OS, ARCH, and USER from the environment, then generates all possible combinations of these values (maintaining canonical order: ENV, OS, ARCH, USER).

Files are loaded in specificity order - more parts means more specific, which means higher precedence.

§Returns

A vector of paths in load order (later paths override earlier ones).

§Examples

With ENV=local, OS=linux, ARCH=amd64, USER=alice, this generates:

  • .env
  • .env.local
  • .env.linux
  • .env.amd64
  • .env.alice
  • .env.local.linux
  • .env.local.amd64
  • .env.local.alice
  • .env.linux.amd64
  • .env.linux.alice
  • .env.amd64.alice
  • .env.local.linux.amd64
  • .env.local.linux.alice
  • .env.local.amd64.alice
  • .env.linux.amd64.alice
  • .env.local.linux.amd64.alice
  • .env.pr-<NUMBER> (if applicable)
Source

pub fn load_env_file( &self, path: &Path, ) -> SecretsResult<HashMap<String, String>>

Loads and decrypts a single .env file, returning key/value pairs.

§Errors

Returns an error if the file cannot be read or if decryption fails.

Source

pub fn parse_and_decrypt( &self, content: &str, path: &Path, ) -> SecretsResult<HashMap<String, String>>

Parses env file content and decrypts encrypted values.

§Errors

Returns an error if the content cannot be parsed or if decryption fails.

Source

pub fn get_var(&self, key: &str) -> SecretsResult<String>

Gets a decrypted environment variable value from the process environment.

If the value is encrypted, it will be automatically decrypted.

§Errors

Returns an error if the variable is not set or if decryption fails.

Source

pub fn get_var_or(&self, key: &str, default: &str) -> String

Gets a decrypted environment variable, or returns a default if not set.

§Examples
use dotenvage::EnvLoader;

let loader = EnvLoader::new()?;
let port = loader.get_var_or("PORT", "8080");
Source

pub fn get_all_variable_names(&self) -> SecretsResult<Vec<String>>

Gets all variable names from all .env* files that would be loaded.

This method uses the standard file-loading algorithm (via resolve_env_paths) to determine which files would be loaded, then collects all unique variable names across those files.

Files are processed in the same order as load(), but this method only collects the variable names without loading them into the environment.

§Returns

A vector of unique variable names found across all .env* files that would be loaded. If a variable appears in multiple files, it only appears once in the result.

Note: AGE key variables (DOTENVAGE_AGE_KEY, AGE_KEY, EKG_AGE_KEY, AGE_KEY_NAME, and any variable ending with _AGE_KEY_NAME) are filtered out for security reasons.

§Errors

Returns an error if any file cannot be read or parsed. Unlike load(), this method fails fast on the first error encountered.

§Examples
use dotenvage::EnvLoader;

let loader = EnvLoader::new()?;
let variable_names = loader.get_all_variable_names()?;
println!("Found {} variables", variable_names.len());
for name in &variable_names {
    println!("  - {}", name);
}
Source

pub fn get_all_variable_names_from_dir( &self, dir: impl AsRef<Path>, ) -> SecretsResult<Vec<String>>

Gets all variable names from all .env* files in a specific directory.

Like get_all_variable_names(), but loads from a specific directory instead of the current directory.

Note: AGE key variables are filtered out for security reasons.

§Errors

Returns an error if any file cannot be read or parsed.

§Examples
use dotenvage::EnvLoader;

let loader = EnvLoader::new()?;
let variable_names = loader.get_all_variable_names_from_dir("./config")?;
Source

pub fn dump_to_writer<W: Write>(&self, writer: W) -> SecretsResult<()>

Write all merged .env variables in KEY=VALUE format to a writer.

Automatically filters out AGE key variables (DOTENVAGE_AGE_KEY, AGE_KEY, EKG_AGE_KEY, AGE_KEY_NAME, and any variable ending with _AGE_KEY_NAME).

This function:

  1. Loads all .env* files in standard order
  2. Merges variables (later files override earlier ones)
  3. Decrypts encrypted values
  4. Filters out AGE key variables
  5. Writes in simple KEY=VALUE format (quotes added when needed)
§Errors

Returns an error if:

  • Writing to the writer fails
  • .env files cannot be loaded
  • Decryption fails for any encrypted value
§Examples
use std::io::Cursor;

use dotenvage::EnvLoader;

let loader = EnvLoader::new()?;
let mut buffer = Vec::new();
loader.dump_to_writer(&mut buffer)?;
let output = String::from_utf8(buffer)?;
println!("{}", output);
Source

pub fn dump_to_writer_from_dir<W: Write>( &self, dir: impl AsRef<Path>, writer: W, ) -> SecretsResult<()>

Write all merged .env variables in KEY=VALUE format to a writer from a specific directory.

Same as dump_to_writer but loads from a specific directory.

§Errors

Returns an error if:

  • Writing to the writer fails
  • .env files cannot be loaded
  • Decryption fails for any encrypted value
Source

pub fn resolve_env() -> String

Resolves the <ENV> placeholder for environment-specific file names.

The environment name is resolved in the following order:

  1. DOTENVAGE_ENV environment variable (preferred)
  2. EKG_ENV environment variable (alternative)
  3. VERCEL_ENV environment variable
  4. NODE_ENV environment variable
  5. Defaults to "local" if none of the above are set

The value is always converted to lowercase.

§Examples
use dotenvage::EnvLoader;

// With DOTENVAGE_ENV=production, returns "production"
// Without any env vars set, returns "local"
let env = EnvLoader::resolve_env();
println!("Environment: {}", env);
Source

pub fn resolve_arch() -> Option<String>

Resolves the <ARCH> placeholder for architecture-specific file names.

The architecture name is resolved from the first available source:

  1. DOTENVAGE_ARCH environment variable (preferred)
  2. EKG_ARCH environment variable (alternative)
  3. CARGO_CFG_TARGET_ARCH environment variable (Cargo build-time, e.g., “x86_64”, “aarch64”)
  4. TARGET environment variable (parsed for arch from target triple, e.g., “x86_64-unknown-linux-gnu” → “x86_64”)
  5. TARGETARCH environment variable (Docker multi-platform builds, e.g., “amd64”, “arm64”)
  6. TARGETPLATFORM environment variable (Docker, parsed for arch, e.g., “linux/arm64” → “arm64”)
  7. RUNNER_ARCH environment variable (GitHub Actions, e.g., “X64”, “ARM64”)
  8. Returns None if none are set
§Supported Architectures

The following architectures are recognized and normalized to canonical names:

  • amd64: AMD64/x86-64 (aliases: x64, x86_64, x86-64)
  • arm64: ARM 64-bit (aliases: aarch64)
  • arm: ARM 32-bit (aliases: armv7, armv7l, armhf)
  • i386: x86 32-bit (aliases: i686, x86)
  • riscv64: RISC-V 64-bit (aliases: riscv64gc)
  • ppc64le: PowerPC 64-bit LE (aliases: powerpc64le)
  • s390x: IBM System/390

Unknown values are passed through as-is (lowercase) for custom use cases.

§Examples
use dotenvage::EnvLoader;

// With TARGETARCH=arm64 (Docker build), resolves to Some("arm64")
// With RUNNER_ARCH=X64 (GitHub Actions), resolves to Some("amd64")
if let Some(arch) = EnvLoader::resolve_arch() {
    println!("Architecture: {}", arch);
}
Source

pub fn resolve_os() -> Option<String>

Resolves the <OS> placeholder for OS-specific file names.

The operating system is resolved from the first available source:

  1. DOTENVAGE_OS environment variable (preferred)
  2. EKG_OS environment variable (alternative)
  3. CARGO_CFG_TARGET_OS environment variable (Cargo build-time, e.g., “linux”, “macos”, “windows”)
  4. TARGET environment variable (parsed from target triple, e.g., “x86_64-unknown-linux-gnu” → “linux”)
  5. RUNNER_OS environment variable (GitHub Actions, e.g., “Linux”, “macOS”, “Windows”)
  6. std::env::consts::OS (runtime detection)
§Supported Operating Systems
  • linux: Linux
  • macos: macOS (aliases: darwin, osx)
  • windows: Windows (aliases: win32, win)
  • freebsd: FreeBSD
  • openbsd: OpenBSD
  • netbsd: NetBSD
  • android: Android
  • ios: iOS
§Examples
use dotenvage::EnvLoader;

// Typically auto-detects from runtime or build-time
if let Some(os) = EnvLoader::resolve_os() {
    println!("OS: {}", os);
}
Source

pub fn resolve_user() -> Option<String>

Resolves the <USER> placeholder for user-specific file names.

The username is resolved from the first available environment variable:

  1. DOTENVAGE_USER (preferred)
  2. EKG_USER
  3. GITHUB_ACTOR (GitHub Actions)
  4. GITHUB_TRIGGERING_ACTOR (GitHub Actions)
  5. GITHUB_REPOSITORY_OWNER (GitHub Actions)
  6. USER (Unix standard)
  7. USERNAME (Windows standard)
  8. Returns None if none are set

The value is always converted to lowercase.

§Examples
use dotenvage::EnvLoader;

// Typically resolves from $USER on Unix or %USERNAME% on Windows
if let Some(user) = EnvLoader::resolve_user() {
    println!("User: {}", user);
}
Source

pub fn resolve_pr_number() -> Option<String>

Resolves the <PR_NUMBER> placeholder for PR-specific file names.

The PR number is only resolved in GitHub Actions pull request contexts:

  1. Checks that GITHUB_EVENT_NAME starts with "pull_request"
  2. Reads from PR_NUMBER environment variable
  3. Falls back to parsing GITHUB_REF (e.g., refs/pull/123/merge)
  4. Returns None if not in a PR context
§Examples
use dotenvage::EnvLoader;

// In GitHub Actions PR, resolves to Some("123")
// Outside of PR context, returns None
if let Some(pr_number) = EnvLoader::resolve_pr_number() {
    println!("PR Number: {}", pr_number);
}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V