envconfig

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

README

envconfig

A lightweight, type-safe Go library for loading configuration from environment variables into structs — with support for defaults, required fields, nested structs, prefix scoping, pointer types, sensitive masking, slices, custom types, time.Duration, and time.Time.

Go Reference License


Features

  • Generic & type-safe — uses Go generics (Load[T]()) for zero-boilerplate usage
  • Struct tags — declarative configuration via env, default, required, sensitive, sep, and envPrefix tags
  • Built-in type supportstring, int, int64, float32, float64, bool, time.Duration, time.Time, pointers to any supported type, and slices of any supported type
  • Nested structs — recursive resolution with optional prefix scoping via envPrefix
  • Pointer fields — pointers are allocated on demand; left nil when the value is absent
  • Custom types — implement the Unmarshaler interface for full control over parsing
  • Sensitive field masking — redact secrets from logs with Mask()
  • Aggregated errors — all missing/invalid fields are reported at once, with fully-qualified field paths

Installation

go get github.com/Shin-9x/envconfig

Requires Go 1.25.6 or later.


Quick Start

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/Shin-9x/envconfig"
)

type DatabaseConfig struct {
    Host string `env:"HOST" default:"localhost"`
    Port int    `env:"PORT" default:"5432"`
}

type Config struct {
    Database DatabaseConfig `envPrefix:"DB_"`
    Debug    bool           `env:"APP_DEBUG"   default:"false"`
    Timeout  time.Duration  `env:"APP_TIMEOUT" default:"30s"`
    APIKey   string         `env:"API_KEY"     required:"true" sensitive:"true"`
    Tags     []string       `env:"APP_TAGS"    default:"web,api" sep:","`
}

func main() {
    cfg, err := envconfig.Load[Config]()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(envconfig.Mask(cfg))
    // Config: {DB_HOST=localhost, DB_PORT=5432, APP_DEBUG=false, APP_TIMEOUT=30s, API_KEY=[*****], APP_TAGS=[web,api]}
}

Struct Tags Reference

Tag Description
env Environment variable name to read. Fields without this tag are skipped.
envPrefix Prefix prepended to all env keys within the tagged struct field. Prefixes are cumulative.
default Fallback value when the variable is unset or empty.
required Mark the field as required. Any non-empty tag value (e.g. "true") triggers the check.
sensitive Set to "true" to redact the value in Mask() output.
sep Separator for slice fields. Defaults to ",".

Supported Types

Go Type Example env value Notes
string hello
int 42
int64 9223372036854775807
float32 3.14
float64 2.718281828
bool true, false, 1, 0
time.Duration 30s, 1h, 500ms
time.Time 2024-01-15T10:30:00Z Parsed as RFC3339
*T any value for T nil if the variable is absent
[]T a,b,c Any of the above as element type

Nested Structs & Prefix Scoping

Nested structs are resolved recursively. Use envPrefix on a struct field to scope its children under a common prefix. Prefixes from outer and inner levels are concatenated.

type DatabaseConfig struct {
    Host string `env:"HOST" default:"localhost"`
    Port int    `env:"PORT" default:"5432"`
}

type Config struct {
    Database DatabaseConfig `envPrefix:"DB_"`
}

This maps DB_HOSTDatabase.Host and DB_PORTDatabase.Port.

Prefixes nest naturally:

type Config struct {
    Prod struct {
        DB DatabaseConfig `envPrefix:"DB_"`
    } `envPrefix:"PROD_"`
}
// resolves PROD_DB_HOST → Config.Prod.DB.Host

Pointer Fields

Fields with pointer types are allocated only when the environment variable is present and non-empty. If the variable is absent and the field is not required, the pointer remains nil.

type Config struct {
    MaxRetries *int `env:"MAX_RETRIES"` // nil if MAX_RETRIES is unset
}

Custom Types via Unmarshaler

Implement the Unmarshaler interface to control how a custom type is parsed:

type Unmarshaler interface {
    UnmarshalEnv(value string) error
}
Example
type LogLevel struct{ level string }

func (l *LogLevel) UnmarshalEnv(value string) error {
    switch value {
    case "DEBUG", "INFO", "WARN", "ERROR":
        l.level = value
        return nil
    default:
        return fmt.Errorf("invalid log level %q, must be one of DEBUG, INFO, WARN, ERROR", value)
    }
}

type Config struct {
    Level LogLevel `env:"LOG_LEVEL" default:"INFO"`
}

Masking Sensitive Fields

Use Mask() to produce a log-safe string representation of your config. Fields tagged with sensitive:"true" are replaced with [*****]. The function handles nested structs, pointer fields, and nil slices transparently.

cfg, _ := envconfig.Load[Config]()
fmt.Println(envconfig.Mask(cfg))
// Config: {DB_HOST=localhost, DB_PORT=5432, API_KEY=[*****], APP_TAGS=[web,api]}

// Also works with a pointer
fmt.Println(envconfig.Mask(&cfg))

Error Handling

Load collects all errors before returning, so you get a complete picture of what is misconfigured rather than fixing problems one at a time. Each error includes the fully-qualified field path to pinpoint exactly where the issue is:

Database.Host: missing required env var DB_HOST
Database.Port: invalid int for DB_PORT: strconv.Atoi: parsing "abc": invalid syntax
cfg, err := envconfig.Load[Config]()
if err != nil {
    log.Fatal(err)
}

License

This project is licensed under the Apache License 2.0.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Load

func Load[T any]() (T, error)

func Mask

func Mask(v any) string

Mask returns a string representation of any struct, masking fields tagged as sensitive:"true".

Types

type Unmarshaler

type Unmarshaler interface {
	UnmarshalEnv(value string) error
}

Unmarshaler is the interface implemented by types that can parse themselves from a raw environment variable string.

UnmarshalEnv receives the raw string value (never empty) and is responsible for populating the receiver. Return a descriptive error if the value is invalid.

Example:

type LogLevel struct{ level string }

func (l *LogLevel) UnmarshalEnv(value string) error {
    switch value {
    case "DEBUG", "INFO", "WARN", "ERROR":
        l.level = value
        return nil
    default:
        return fmt.Errorf("invalid log level %q, must be one of DEBUG, INFO, WARN, ERROR", value)
    }
}

Jump to

Keyboard shortcuts

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