envconfig

A lightweight, dependency-free Go library that populates typed structs from environment variables using reflection and struct tags.

Library
Go
vv1.4.0
5,469 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
45 /100 Fair
Development Activity 0
Maintenance 20
Community 60
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
63 /100 Good
Architecture 65
Code Quality 72
Innovation 78
Learning Curve 35

envconfig is a small, dependency-free Go library from Kelsey Hightower for loading application configuration out of environment variables into a plain struct. Instead of hand-writing os.Getenv calls and manual type conversions, you define a Specification struct with typed fields, call envconfig.Process with a prefix, and reflection walks the struct filling in each field from PREFIX_FIELDNAME (or a custom key via the envconfig tag).

It supports defaults, required fields, automatic camelCase-to-SNAKE_CASE splitting, embedded structs, slices and maps parsed from comma/colon-delimited strings, and custom decoding via the Decoder, Setter (flag.Value-compatible), TextUnmarshaler, and BinaryUnmarshaler interfaces. A companion Usage/Usagef API can print a self-documenting table of every configuration variable the program accepts, generated straight from the struct definition.

What You Get

  • A single Process(prefix, &spec) call that maps environment variables to struct fields by name
  • Struct tag support for default, required, envconfig (custom key), split_words, and ignored
  • Built-in parsing for strings, all int/uint/float sizes, bool, time.Duration, slices, and maps
  • Pluggable custom decoding via Decoder, Setter, TextUnmarshaler, and BinaryUnmarshaler interfaces
  • A Usage/Usagef helper that renders a formatted table of every recognized environment variable

Common Use Cases

  • Loading twelve-factor app configuration (ports, timeouts, feature flags) at process startup
  • Generating self-documenting help output listing every environment variable a service reads
  • Enforcing required configuration values fail fast with required:“true” before a service starts serving traffic
  • Decoding structured values like IP addresses or custom JSON blobs from a single environment variable via a custom Decoder

Under The Hood

Architecture

The package centers on gatherInfo in envconfig.go, which walks a struct via reflect, resolving each field’s environment-variable key from its tags (or a split_words-derived name) and recursing into embedded/nested structs; Process then iterates that gathered varInfo list, looks up each key with a build-tag-selected lookupEnv (env_os.go uses os.LookupEnv on modern Go, env_syscall.go falls back to syscall.Getenv for pre-1.5 compatibility — a legacy artifact retained from the package’s early-2010s origins), applies defaults/required checks, and dispatches to processField’s type switch for the actual conversion. usage.go is a separate, self-contained file that reuses gatherInfo to drive a text/template-based table renderer, keeping documentation generation decoupled from parsing. The design is a flat, single-package module with no internal layering beyond this — appropriate for its narrow scope.

Tech Stack

Pure Go standard library: reflect and regexp for the tag-driven field walk, encoding (TextUnmarshaler/BinaryUnmarshaler) and a local Decoder/Setter pair for extensibility, strconv and time for scalar conversions, and text/template/text/tabwriter for the usage table. There are zero third-party runtime dependencies. go.mod declares go 1.20 with no other entries. CI is a single GitHub Actions workflow (.github/workflows/go.yml) that runs go build ./... and go test -v ./... against Go 1.20 on push and pull requests to master — no linter step is configured.

Code Quality

Test coverage is extensive relative to the package’s size: roughly 40 test functions spread across envconfig_test.go, usage_test.go, and a build-tag-gated envconfig_1.8_test.go, all written against the standard testing package with direct t.Errorf assertions (no third-party assertion library). Error handling is explicit and typed — a dedicated ParseError struct wraps key/field/type/value context around every conversion failure, and ErrInvalidSpecification is a clear sentinel for misuse. Naming is consistent and idiomatic Go throughout. There is no .golangci.yml or explicit lint step in CI, so style enforcement relies on convention rather than tooling.

API Design The public surface is deliberately small: a single Process(prefix, &spec) call covers the common case, and the zero-config default (upper-snake-cased field name) means most structs need no struct tags at all. Opt-in specialization — default, required, envconfig, split_words, ignored — keeps the common path boilerplate-free while still supporting overrides for edge cases like acronym-heavy field names. Custom decoding is pluggable through four well-established interface shapes (a local Decoder, flag.Value-compatible Setter, and the two standard-library encoding unmarshaler interfaces) rather than inventing a bespoke hook, so existing types often work with no changes. The Usage/Usagef/Usaget family is a genuinely useful extra: free, always-in-sync --help-style documentation generated from the same struct that drives parsing, which most comparable env-to-struct libraries do not offer.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers