envstruct

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2026 License: MIT Imports: 12 Imported by: 0

README

envstruct

A Go library that populates struct fields from environment variables. Drop-in replacement for kelseyhightower/envconfig.

Install

go get github.com/agentine/envstruct

Quick Start

package main

import (
    "fmt"
    "log"

    "github.com/agentine/envstruct"
)

type Config struct {
    Host  string `default:"localhost" desc:"Server hostname"`
    Port  int    `default:"8080"     desc:"Server port"`
    Debug bool   `                   desc:"Enable debug mode"`
}

func main() {
    var c Config
    if err := envstruct.Process("APP", &c); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Listening on %s:%d\n", c.Host, c.Port)
}

Set environment variables and run:

APP_HOST=0.0.0.0 APP_PORT=9090 go run main.go
# Listening on 0.0.0.0:9090

API Reference

Functions
Process(prefix string, spec interface{}) error

Populates the struct pointed to by spec with values from environment variables. The prefix is prepended to each field's env var name (uppercased, joined with _).

Returns a joined error of all field errors encountered. Returns an error immediately if spec is not a non-nil pointer to a struct.

var cfg Config
if err := envstruct.Process("MYAPP", &cfg); err != nil {
    log.Fatal(err)
}
MustProcess(prefix string, spec interface{})

Like Process but panics on error. Useful in main() when a misconfigured environment is always fatal.

var cfg Config
envstruct.MustProcess("MYAPP", &cfg)
Usage(prefix string, spec interface{}, out io.Writer) error

Writes a human-readable table of expected environment variables to out, including their type, default value, and description.

envstruct.Usage("APP", &Config{}, os.Stderr)

Output:

  APP_HOST   string  [default: localhost]  Server hostname
  APP_PORT   int     [default: 8080]       Server port
  APP_DEBUG  bool                          Enable debug mode
Interfaces

Types can implement any of the following interfaces to control their own decoding. Interface methods are checked via pointer receivers.

Decoder
type Decoder interface {
    Decode(value string) error
}

The primary custom decoding interface. If a field's type implements Decoder, Decode is called with the raw environment variable string.

Setter
type Setter interface {
    Set(value string) error
}

Compatibility interface for types that implement kelseyhightower/envconfig's Setter interface. Checked after Decoder.

encoding.TextUnmarshaler

Standard library interface. If a type implements encoding.TextUnmarshaler, UnmarshalText is called. Checked after Setter.

Custom type example:

type LogLevel int

const (
    LevelInfo LogLevel = iota
    LevelWarn
    LevelError
)

func (l *LogLevel) Decode(s string) error {
    switch strings.ToLower(s) {
    case "info":  *l = LevelInfo
    case "warn":  *l = LevelWarn
    case "error": *l = LevelError
    default:      return fmt.Errorf("unknown level: %s", s)
    }
    return nil
}

type Config struct {
    Level LogLevel `default:"info"`
}
// LOG_LEVEL=warn envstruct.Process("LOG", &cfg)
Error Types
ParseError

Returned when an environment variable value cannot be parsed into the target type.

type ParseError struct {
    FieldName string  // struct field name
    EnvVar    string  // full env var key (e.g. APP_PORT)
    Value     string  // the raw string value that failed to parse
    TypeName  string  // target Go type name
    Err       error   // underlying parse error
}

ParseError implements Unwrap(), so it works with errors.As and errors.Is.

RequiredError

Returned when a field marked required has no environment variable set and no default.

type RequiredError struct {
    FieldName string  // struct field name
    EnvVar    string  // full env var key
}

Supported Types

Type Example env value
string hello
bool true, false, 1, 0
int, int8..int64 42, -1
uint, uint8..uint64 42
float32, float64 3.14
time.Duration 5s, 100ms, 1h30m
url.URL / *url.URL https://example.com
[]T (any scalar T) a,b,c
map[string]T key1=val1,key2=val2
Custom Decoder User-defined
Custom Setter envconfig compat
encoding.TextUnmarshaler User-defined
Slices

Slice fields are split on , by default. Use the envSeparator tag to override the delimiter.

type Config struct {
    Tags    []string `desc:"Comma-separated tags"`         // TAGS=a,b,c
    Paths   []string `envSeparator:":" desc:"Colon paths"` // PATHS=/a:/b:/c
}
Maps

Map fields are split on ,, with each element parsed as key=value:

type Config struct {
    Labels map[string]string // LABELS=env=prod,region=us-east-1
}

Struct Tags

Tag Description
env:"VAR_NAME" Override env var name for this field
env:"VAR_NAME,required" Mark field as required (error if unset and no default)
env:"-" Skip field entirely
envconfig:"VAR_NAME" Alias for env — envconfig compatibility
default:"value" Default value if env var is unset
envDefault:"value" Alias for default — envconfig compatibility
envSeparator:":" Custom separator for slice fields (default: ,)
envExpand:"true" Expand $VAR references in the value via os.ExpandEnv
desc:"description" Field description shown in Usage() output
envExpand example
type Config struct {
    DataDir string `default:"$HOME/.myapp" envExpand:"true"`
}
// DataDir will expand to /home/user/.myapp (or whatever $HOME is set to)

Nested Structs

Named nested struct fields are flattened with _ separators:

type DB struct {
    Host string
    Port int
}
type Config struct {
    Database DB
}
// envstruct.Process("APP", &cfg) reads:
//   APP_DATABASE_HOST
//   APP_DATABASE_PORT

Embedded (anonymous) structs are flattened without adding a prefix segment:

type Base struct {
    LogLevel string
}
type Config struct {
    Base                // embedded — no extra segment added
    Port int
}
// envstruct.Process("APP", &cfg) reads:
//   APP_LOG_LEVEL
//   APP_PORT
Pointer-to-struct

Pointer-to-struct fields are automatically allocated only when at least one nested env var is actually set. If no env var matches, the pointer remains nil.

type TLSConfig struct {
    Cert string
    Key  string
}
type Config struct {
    TLS *TLSConfig
}
// If neither APP_TLS_CERT nor APP_TLS_KEY is set, cfg.TLS == nil.
// If either is set, cfg.TLS is allocated and populated.

Usage Text

envstruct.Usage("APP", &Config{}, os.Stderr)

Outputs a table of all expected environment variables with their type, default value, and description. Useful to print in response to a --help flag or on startup error.

Migration from envconfig

envstruct is a drop-in replacement. Function signatures are identical:

// Before
import "github.com/kelseyhightower/envconfig"
envconfig.Process("APP", &config)
envconfig.MustProcess("APP", &config)

// After
import "github.com/agentine/envstruct"
envstruct.Process("APP", &config)
envstruct.MustProcess("APP", &config)

Both env and envconfig struct tags are supported for smooth migration. Both default and envDefault tags are also recognized.

If your types implement envconfig.Setter (a Set(string) error method), they will work without modification.

License

MIT

Documentation

Overview

Package envstruct populates struct fields from environment variables.

It is a drop-in replacement for kelseyhightower/envconfig with the same Process(prefix, &spec) function signature.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MustProcess

func MustProcess(prefix string, spec interface{})

MustProcess is like Process but panics on error.

func Process

func Process(prefix string, spec interface{}) error

Process populates the struct pointed to by spec with values from environment variables. The prefix is prepended to each field name (or tag override) when looking up environment variables.

Example
package main

import (
	"fmt"
	"os"

	"github.com/agentine/envstruct"
)

func main() {
	os.Setenv("APP_HOST", "localhost")
	os.Setenv("APP_PORT", "8080")
	defer os.Unsetenv("APP_HOST")
	defer os.Unsetenv("APP_PORT")

	type Config struct {
		Host string
		Port int
	}
	var c Config
	err := envstruct.Process("APP", &c)
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Printf("Host=%s Port=%d\n", c.Host, c.Port)
}
Output:
Host=localhost Port=8080
Example (Nested)
package main

import (
	"fmt"
	"os"

	"github.com/agentine/envstruct"
)

func main() {
	os.Setenv("APP_DATABASE_HOST", "db.local")
	os.Setenv("APP_DATABASE_PORT", "5432")
	defer os.Unsetenv("APP_DATABASE_HOST")
	defer os.Unsetenv("APP_DATABASE_PORT")

	type DB struct {
		Host string
		Port int
	}
	type Config struct {
		Database DB
	}
	var c Config
	err := envstruct.Process("APP", &c)
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Printf("DB=%s:%d\n", c.Database.Host, c.Database.Port)
}
Output:
DB=db.local:5432
Example (Required)
package main

import (
	"fmt"

	"github.com/agentine/envstruct"
)

func main() {
	type Config struct {
		Secret string `env:"SECRET,required"`
	}
	var c Config
	err := envstruct.Process("APP", &c)
	if err != nil {
		fmt.Println("got expected error")
		return
	}
	fmt.Println("unexpected success")
}
Output:
got expected error

func Usage

func Usage(prefix string, spec interface{}, out io.Writer) error

Usage writes a usage message describing the environment variables expected by spec to the given writer.

Example
package main

import (
	"os"

	"github.com/agentine/envstruct"
)

func main() {
	type Config struct {
		Host  string `default:"localhost" desc:"Server hostname"`
		Port  int    `default:"8080" desc:"Server port"`
		Debug bool   `desc:"Enable debug mode"`
	}
	_ = envstruct.Usage("APP", &Config{}, os.Stdout)
}
Output:
  KEY        TYPE    DEFAULT               DESCRIPTION
  APP_HOST   string  [default: localhost]  Server hostname
  APP_PORT   int     [default: 8080]       Server port
  APP_DEBUG  bool                          Enable debug mode

Types

type Decoder

type Decoder interface {
	Decode(value string) error
}

Decoder is implemented by types that can decode themselves from a string.

type ParseError

type ParseError struct {
	FieldName string
	EnvVar    string
	Value     string
	TypeName  string
	Err       error
}

ParseError is returned when an environment variable value cannot be parsed into the target type.

func (*ParseError) Error

func (e *ParseError) Error() string

func (*ParseError) Unwrap

func (e *ParseError) Unwrap() error

type RequiredError

type RequiredError struct {
	FieldName string
	EnvVar    string
}

RequiredError is returned when a required environment variable is missing.

func (*RequiredError) Error

func (e *RequiredError) Error() string

type Setter

type Setter interface {
	Set(value string) error
}

Setter is implemented by types that can set themselves from a string. This interface exists for compatibility with kelseyhightower/envconfig.

Jump to

Keyboard shortcuts

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