env
A simple, zero-dependencies Go library that parses environment variables directly into struct fields using tags.
Repository Health
Technical Analysis
env is a small, dependency-free Go library for turning environment variables into typed configuration structs. Instead of hand-writing os.Getenv calls and manual type conversions for every setting, you annotate a struct with env tags and call env.Parse (or the generic env.ParseAs[T]) to populate it in one pass, with built-in support for primitives, slices, maps, time.Duration, time.Location, url.URL, and any type implementing encoding.TextUnmarshaler.
Beyond basic parsing, it supports default values (envDefault), required and non-empty enforcement (required, notEmpty), variable expansion (,expand), loading a value from a file path (,file), prefixing nested structs (envPrefix), custom separators for slices and maps, and a hook (OnSet) for observing every value as it’s assigned. Custom parsers can be registered per-type via FuncMap, and ParseWithOptions exposes fine-grained control over tag names, the source environment map, and default-value behavior.
The project has been stable and widely adopted for years (created 2015, on major version v11), is used in production by platforms like Encore, and the maintainer explicitly considers it feature-complete — new work is limited to bug fixes and carefully considered additions. Its zero-dependency footprint and predictable, tag-driven API make it a common default choice for twelve-factor-style Go services that read configuration from the environment.
What You Get
- One-call parsing of environment variables into any struct via
Parse,ParseWithOptions, or the genericParseAs[T]/ParseAsWithOptions[T] - Built-in parsers for all primitive Go types plus
time.Duration,time.Location,url.URL, slices, maps, and pointers, with support for registering custom parsers viaFuncMap - Declarative validation and defaults through tag options:
required,notEmpty,envDefault,,expandfor variable interpolation, and,filefor file-backed values - Nested-struct support with
envPrefixto namespace environment variable names, andenvSeparator/envKeyValSeparatorto control slice and map parsing - An
OnSethook that fires for every field as it is populated, useful for logging or auditing configuration at startup - Structured, typed errors (
ParseError,VarIsNotSetError,EmptyVarError,NoParserError, etc.) aggregated into a singleAggregateErrorthat supportserrors.Is/errors.As
Common Use Cases
- Loading twelve-factor-app configuration (ports, hostnames, credentials, feature flags) into a typed
Configstruct at service startup - Enforcing required environment variables in CI/CD and containerized deployments, failing fast with a clear aggregated error instead of a nil-pointer panic later
- Reading secrets or credentials mounted as files (e.g. Docker/Kubernetes secrets) into config fields via the
,filetag option instead of plaintext env vars - Namespacing configuration for multiple instances of the same component (e.g. two database connections) using
envPrefixon nested structs - Providing sane defaults for local development while requiring explicit values in production, via
envDefaultcombined withRequiredIfNoDef
Under The Hood
Architecture
Parsing flows through a small, linear pipeline in env.go: Parse/ParseWithOptions build an Options value (merging user overrides over defaultOptions() via reflection-based mergeOptions), then hand off to parseInternal, which validates the input is a pointer to a struct and calls doParse. doParse walks each struct field with reflect, delegating to doParseField for scalar/aggregate fields and doParseSlice for slices of nested structs (each element gets its own prefixed Options via optionsWithSliceEnvPrefix), recursing into nested structs so envPrefix composes naturally. Field-level tag parsing (parseFieldParams), value lookup (get, getOr, getFromFile), and type coercion (set, handleSlice, handleMap, parseTextUnmarshalers) are each isolated into their own functions, so the recursive struct-walking logic never touches string-to-type conversion directly — a clean separation that keeps the reflection-heavy core auditable despite touching every exported field in a struct tree.
Tech Stack
The module (github.com/caarlos0/env/v11, Go 1.18+) has zero runtime dependencies — everything is built on the standard library (reflect, encoding, net/url, os, strconv, strings, time, unicode). Build and release tooling is handled by a Makefile plus GoReleaser, and CI runs via GitHub Actions across Ubuntu/macOS/Windows and three Go versions (1.18, oldstable, stable), with golangci-lint (.golangci.yml), Semgrep, CodeQL, and a Codecov upload gating merges.
Code Quality
The test suite (env_test.go) contains well over a hundred test functions covering scalar types, slices, maps, nested structs, prefixes, defaults, required/notEmpty combinations, file-backed values, and custom parsers, alongside a dedicated example_test.go of runnable Example* functions that double as documentation on pkg.go.dev. Errors are modeled as distinct exported types (ParseError, VarIsNotSetError, NoParserError, etc.) rather than opaque strings, aggregated through an AggregateError that implements Unwrap() []error and a custom Is for errors.Is compatibility — a deliberately typed, inspectable error-handling style rather than sentinel strings.
What Makes It Unique
Rather than a runtime config-loading framework with file formats and remote backends, env stays narrowly scoped to “struct tags in, typed values out,” but pushes that scope further than most equivalents: generics-based ParseAs[T] avoids a pre-allocated pointer argument, ,file transparently swaps a value for file contents (useful for secret-mounted configs), and ,expand performs recursive environment-variable interpolation. Combined with its zero-dependency footprint and long-standing API stability (feature-complete per the maintainer, on major version v11 after eleven years), it optimizes for being a safe, boring default rather than the most feature-rich option.
Used by 3 apps in this directory
Anarlog
Note Taking · AI Assistants · Productivity
Anarlog is an open-source, local-first AI meeting notetaker that records, transcribes, and summarizes meetings entirely on your device — no cloud lock-in, no mandatory account, and every note saved as a plain markdown file you own forever.
Bytebase
Devops
An open-source database CI/CD and DevSecOps platform — schema migration review, GitOps-driven changes, data masking, and access control across MySQL, PostgreSQL, Oracle, Snowflake, MongoDB, and more.
Digger
Devops · Automation · Developer Tools
Run Terraform and OpenTofu natively inside your existing CI pipeline — no separate runners, no third-party secrets, no extra compute costs.