env

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: MIT Imports: 13 Imported by: 0

README

env

CI Go Reference Go Report Card

Blazing-fast, zero-allocation environment configuration for Go.

github.com/gopherust-io/env parses environment variables into typed structs using compile-time code generation. No reflection at runtime. No external dependencies. One os.Environ() pass, then direct field assignment.

Quick links: Architecture · Getting started · Examples · Changelog

  caarlos0/env   11,619 ns/op   220 allocs
  viper           3,146 ns/op    70 allocs
  stdlib            150 ns/op     0 allocs
  env                  74 ns/op     0 allocs

Benchmark note: these numbers come from the project bench suite on identical fixtures and should be treated as directional. Re-run on your hardware for release decisions: make bench-remote VERSION=<tag>.

New here?docs/GETTING_STARTED.md (copy-paste guide, CI, troubleshooting)


Start in 3 steps

1. Install

go get github.com/gopherust-io/env@latest
go install github.com/gopherust-io/env/cmd/envgen@latest

2. Struct + generate

package config

//go:generate envgen -type Config -output config_env_gen.go

type Config struct {
    Port  int    `env:"PORT" default:"8080"`
    Debug bool   `env:"DEBUG"`
    Host  string `env:"HOST" default:"localhost"`
}
go generate ./...
# or: envgen -type Config
# list structs: envgen -list

3. Load

cfg, err := config.LoadConfig()
if err != nil {
    log.Fatal(err)
}
log.Printf("%+v", cfg.Masked()) // safe if you use sensitive:"true"

Optional local .env: _ = env.LoadDotEnv(".env") before LoadConfig().

Full-featured example: examples/basic. Minimal: examples/minimal.

When not to use env

  • You need dynamic/untyped runtime schemas from arbitrary keys.
  • Your config changes shape frequently and code generation is not acceptable.
  • You prefer convenience over strict, explicit typed parsing and compile-time setup.

For those cases, reflection-based config loaders can be a better fit.


Cheatsheet

I want to… Do this
List struct names envgen -list
Regenerate loaders go generate ./...
Load config LoadConfig()
Reload after env change ReloadConfig(&cfg)
Log without secrets cfg.Masked()
Skip codegen (dev only) reflectenv.Parse(&cfg)
Nested fields DB Database `prefix:"DB_"`
${VAR} in values `expand:"true"` on field

How it works

flowchart LR
    subgraph compile [Compile time]
        Struct[Config struct]
        Envgen[envgen]
        Gen[config_env_gen.go]
        Struct --> Envgen --> Gen
    end
    subgraph runtime [Runtime]
        Snap[EnvSnapshot]
        Load[LoadConfig]
        Snap --> Load
    end
    Gen --> Load
  1. Define a struct with env tags.
  2. go generate runs envgenLoadConfig, ReloadConfig, Masked().
  3. LoadConfig() indexes the environment once and assigns fields with zero reflection.

Struct tags

Tag Description
env:"KEY" Environment variable name
default:"..." Value when unset
required:"true" Error if unset and no default
prefix:"FOO_" Prefix for nested struct fields
sep:"," Slice separator (default ,)
kvsep:":" Map key/value separator (default :)
layout:"..." time.Time parse layout (default RFC3339)
expand:"true" Expand ${VAR} and $VAR in values
sensitive:"true" Redact in Masked()
env:"-" Skip field

Nested prefixes compose: prefix:"DB_" + env:"HOST"DB_HOST.


Generated API

Function Description
LoadConfig() Parse env into Config
ReloadConfig(cfg *Config) Re-parse env in-place
LoadConfigFrom(snap) Parse from a custom snapshot
MustLoadConfig() Panics on error
(Config) Masked() Copy with sensitive fields redacted

Errors are collected in one pass:

env: DB.Host (DB_HOST): required; Port (PORT): parse: strconv.Atoi: parsing "abc": invalid syntax

Local development (.env)

_ = env.LoadDotEnv(".env")
cfg, err := config.LoadConfig()

LoadDotEnv fills unset variables from a file and refreshes the snapshot. Existing process variables are preserved.

Read-only merge without touching os.Environ():

snap, err := env.SnapshotWithDotEnv(".env")
cfg, err := config.LoadConfigFrom(snap)

Variable expansion

BaseURL string `env:"BASE_URL" default:"${NATS_URL}/api" expand:"true"`

Supports ${VAR} and $VAR syntax.


Hot reload

cfg, _ := config.LoadConfig()
os.Setenv("PORT", "9090")
_ = config.ReloadConfig(&cfg)

Cross-package nested structs

import "myapp/internal/db"

type Config struct {
    DB db.Database `prefix:"DB_"`
}

Reflection fallback (opt-in)

import "github.com/gopherust-io/env/reflectenv"

var cfg Config
reflectenv.Parse(&cfg)

Slower than codegen — use envgen in production.


Custom types

type Mode string

func (m *Mode) UnmarshalEnv(key, value string) error {
    switch value {
    case "dev", "staging", "prod":
        *m = Mode(value)
        return nil
    default:
        return fmt.Errorf("unknown mode %q", value)
    }
}

Migration from caarlos0/env

caarlos0/env env
env.Parse(&cfg) LoadConfig()
envDefault:"8080" default:"8080"
envPrefix:"DB_" prefix:"DB_"
env:"HOST,required" env:"HOST" required:"true"

Performance

make bench-remote VERSION=v0.4.0
Fixture env caarlos0/env Speedup
10 fields 74 ns, 0 allocs 11,619 ns, 220 allocs 157×
50 fields 398 ns, 0 allocs 18,373 ns, 298 allocs 46×
100 fields 946 ns, 0 allocs 26,236 ns, 410 allocs 28×

Runtime API

snap := env.Snapshot()
snap.Lookup("PORT")
env.ParseInt("8080")
env.LoadDotEnv(".env")
env.Reload()

Compatibility and stability

  • Supported Go version: follow go.mod in this repository.
  • Public generated API (LoadConfig, ReloadConfig, Masked) is stable across patch releases.
  • Breaking changes are called out in CHANGELOG.md.

Changelog

See CHANGELOG.md.

Contributing · Security

License

MIT — see LICENSE.

Documentation

Overview

Package env is a codegen-first environment variable parser for Go. Use cmd/envgen to generate type-specific loaders with zero runtime reflection.

Index

Constants

View Source
const SensitiveMask = "***"

SensitiveMask replaces sensitive fields in generated Masked() output.

Variables

This section is empty.

Functions

func AppendParse

func AppendParse(errs *[]FieldError, field, key, value string, parseErr error)

func AppendRequired

func AppendRequired(errs *[]FieldError, field, key string)

func BytesToString added in v0.5.0

func BytesToString(b []byte) string

BytesToString returns a string view of b without copying.

func Expand added in v0.2.0

func Expand(s string, snap *EnvSnapshot) string

Expand replaces ${VAR} and $VAR references using values from snap.

func IsEmpty added in v0.5.0

func IsEmpty(s string) bool

IsEmpty reports whether s is empty.

func LoadDotEnv added in v0.2.0

func LoadDotEnv(path string) error

LoadDotEnv loads variables from path into the process environment. Existing variables are not overwritten. The cached snapshot is refreshed.

func NewError

func NewError(fields []FieldError) error

NewError returns nil when fields is empty.

func ParseBool

func ParseBool(s string) (bool, error)

func ParseDotEnv added in v0.2.0

func ParseDotEnv(data []byte) (map[string]string, error)

ParseDotEnv parses dotenv content. Supports # comments and quoted values.

func ParseDotEnvFile added in v0.2.0

func ParseDotEnvFile(path string) (map[string]string, error)

ParseDotEnvFile reads KEY=VALUE pairs from a dotenv file.

func ParseDuration

func ParseDuration(s string) (time.Duration, error)

func ParseFloat32

func ParseFloat32(s string) (float32, error)

func ParseFloat64

func ParseFloat64(s string) (float64, error)

func ParseInt

func ParseInt(s string) (int, error)

func ParseInt8

func ParseInt8(s string) (int8, error)

func ParseInt16

func ParseInt16(s string) (int16, error)

func ParseInt32

func ParseInt32(s string) (int32, error)

func ParseInt64

func ParseInt64(s string) (int64, error)

func ParseIntSlice

func ParseIntSlice(s, sep string) ([]int, error)

func ParseString

func ParseString(s string) (string, error)

func ParseStringMap

func ParseStringMap(s, sep, kvSep string) (map[string]string, error)

func ParseStringSlice

func ParseStringSlice(s, sep string) ([]string, error)

func ParseTime added in v0.2.0

func ParseTime(s, layout string) (time.Time, error)

func ParseUint

func ParseUint(s string) (uint, error)

func ParseUint8

func ParseUint8(s string) (uint8, error)

func ParseUint16

func ParseUint16(s string) (uint16, error)

func ParseUint32

func ParseUint32(s string) (uint32, error)

func ParseUint64

func ParseUint64(s string) (uint64, error)

func Reload added in v0.4.0

func Reload()

Reload refreshes the cached snapshot from os.Environ(). Generated ReloadConfig calls this before re-parsing.

func ResetSnapshot

func ResetSnapshot()

ResetSnapshot rebuilds the cached snapshot. Concurrent Reload/ResetSnapshot calls coalesce to one environ rebuild.

func StringToBytes added in v0.5.0

func StringToBytes(s string) []byte

StringToBytes returns a read-only view of s as a []byte without copying.

Types

type EnvSnapshot

type EnvSnapshot struct {
	// contains filtered or unexported fields
}

EnvSnapshot holds an indexed view of environment variables.

func FromEnviron

func FromEnviron(environ []string) *EnvSnapshot

func FromMap

func FromMap(vars map[string]string) *EnvSnapshot

func Snapshot

func Snapshot() *EnvSnapshot

Snapshot returns a cached process environment index. The index is built once from os.Environ() until ResetSnapshot is called. Concurrent first callers share a single FromEnviron via singleflight.

func SnapshotWithDotEnv added in v0.2.0

func SnapshotWithDotEnv(paths ...string) (*EnvSnapshot, error)

SnapshotWithDotEnv builds a snapshot from dotenv files overlaid with os.Environ(). Process environment values take precedence over file values.

func (*EnvSnapshot) Len

func (s *EnvSnapshot) Len() int

func (*EnvSnapshot) Lookup

func (s *EnvSnapshot) Lookup(key string) (string, bool)

type Error

type Error struct {
	Fields []FieldError
	// contains filtered or unexported fields
}

Error collects every field error from one parse pass.

func (*Error) Error

func (e *Error) Error() string

type FieldError

type FieldError struct {
	Err    error
	Field  string
	EnvKey string
	Op     string
	Value  string
}

FieldError is a single field-level configuration error.

func (FieldError) Error

func (e FieldError) Error() string

type Unmarshaler

type Unmarshaler interface {
	UnmarshalEnv(key, value string) error
}

Unmarshaler parses a custom type from a raw environment value.

Directories

Path Synopsis
cmd
envgen command
examples
basic/cmd command
internal
tag

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL