Skip to content

Parse environment variables into Go structs with minimal boilerplate and first-class support for complex data structures

License

Notifications You must be signed in to change notification settings

sethpollack/envcfg

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

envcfg

Parse environment variables into Go structs with minimal boilerplate and first-class support for complex data structures

Badges

Go Reference Go Report Card Coverage Test Status Release License

Key Features

  • 🚀 Intuitive struct parsing with minimal boilerplate
  • 📦 Zero dependencies (TODO)
  • 🎯 Flexible prefix matching for nested fields
  • 🧩 First-class support for complex data structures:
    • Nested structs
    • Slices: delimited, indexed, structs
    • Maps: delimited, flat keys, structs
  • 🛠️ Highly customizable with pluggable components

Table of Contents

Installation

go get github.com/sethpollack/envcfg

Quick Start

Set the following environment variables:

# string
export NAME=name
# integer
export PORT=8080
# float
export RATE=1.23
# boolean
export IS_ENABLED=true
# duration
export TIMEOUT=60s
# nested struct
export REDIS_HOST=localhost
export REDIS_PORT=6379
# delimited slice
export TAGS=tag1,tag2,tag3
# indexed slice
export PORTS_0=8080
export PORTS_1=9090
# slice of structs
export SERVERS_0_HOST=localhost1
export SERVERS_0_PORT=8080
export SERVERS_1_HOST=localhost2
export SERVERS_1_PORT=9090
# key-value map
export LABELS=key1:value1,key2:value2
# flat map
export SETTINGS_KEY1=1
export SETTINGS_KEY2=2
# map of structs
export DATABASES_PRIMARY_HOST=localhost1
export DATABASES_PRIMARY_PORT=6379
export DATABASES_SECONDARY_HOST=localhost2
export DATABASES_SECONDARY_PORT=6380

Parse the environment variables into a struct:

package main

import (
	"fmt"
	"time"

	"github.com/sethpollack/envcfg"
)

func main() {
	type ServerConfig struct {
		Host string
		Port int
	}

	type Config struct {
		Name      string
		Port      int
		Rate      float64
		IsEnabled bool
		Timeout   time.Duration

		Redis ServerConfig

		Tags    []string
		Ports   []int
		Servers []ServerConfig

		Labels    map[string]string
		Settings  map[string]int
		Databases map[string]ServerConfig

	}

	cfg := Config{}
	if err := envcfg.Parse(&cfg); err != nil {
		panic(err)
	}

	fmt.Printf(`Config:
  Name: %s
  Port: %d
  Rate: %.2f
  IsEnabled: %t
  Timeout: %s
  Redis:
    Host: %s
    Port: %d
  Tags: %v
  Ports: %v
  Servers: [
    {Host: %s, Port: %d},
    {Host: %s, Port: %d}
  ]
  Labels: %v
  Settings: %v
  Databases: {
    primary: {Host: %s, Port: %d},
    secondary: {Host: %s, Port: %d}
  }
`,
		cfg.Name, cfg.Port, cfg.Rate, cfg.IsEnabled, cfg.Timeout,
		cfg.Redis.Host, cfg.Redis.Port,
		cfg.Tags, cfg.Ports,
		cfg.Servers[0].Host, cfg.Servers[0].Port,
		cfg.Servers[1].Host, cfg.Servers[1].Port,
		cfg.Labels, cfg.Settings,
		cfg.Databases["primary"].Host, cfg.Databases["primary"].Port,
		cfg.Databases["secondary"].Host, cfg.Databases["secondary"].Port,
	)
}

Results:

Config:
  Name: name
  Port: 8080
  Rate: 1.23
  IsEnabled: true
  Timeout: 1m0s
  Redis:
    Host: localhost
    Port: 6379
  Tags: [tag1 tag2 tag3]
  Ports: [8080 9090]
  Servers: [
    {Host: localhost1, Port: 8080},
    {Host: localhost2, Port: 9090}
  ]
  Labels: map[key1:value1 key2:value2]
  Settings: map[key1:1 key2:2]
  Databases: {
    primary: {Host: localhost1, Port: 6379},
    secondary: {Host: localhost2, Port: 6380}
  }

Tip

The example above demonstrates the three supported syntaxes for both slices and maps:

  • Slices:
    • delimited TAGS=tag1,tag2,tag3
    • indexed PORTS_0=8080
    • struct SERVERS_0_HOST=localhost
  • Maps:
    • key-value pairs LABELS=key1:value1
    • flat keys SETTINGS_KEY1=1
    • struct DATABASES_PRIMARY_HOST=localhost

Types

  • string
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • bool
  • float32, float64
  • time.Duration
  • struct
  • slices - of any supported type
  • maps - keys and values of any supported type

Decoders

  • envcfg.Decoder
  • flag.Value
  • encoding.TextUnmarshaler
  • encoding.BinaryUnmarshaler

Struct Tags

Name Description Default Example Tag Example Option
default Default value when environment variable is not set - default:"8080" env:",default=8080"
required Mark field as required false required:"true" env:",required"
notEmpty Ensure value is not empty false notEmpty:"true" env:",notEmpty"
expand Expand environment variables in value false expand:"true" env:",expand"
file Load value from file false file:"true" env:",file"
delim Delimiter for array values , delim:";" env:",delim=;"
sep Separator for map key-value pairs : sep:"=" env:",sep="
match Match strategy for environment variables prefix match:"exact" env:",match=exact"
init Initialize nil pointers values init:"always" env:",init=always"
ignore Ignore field false ignore:"true" env:",ignore" or env:"-"
decodeunset Decode unset environment variables false decodeunset:"true" env:",decodeunset"

Match Options

  • prefix - Match variables with field's prefix (default)
  • exact - Match only exact variable names
  • best - Try prefix match, then exact match

Init Options

  • values - Initialize when values are present (default)
  • always - Always initialize nil pointers
  • never - Never initialize nil pointers

Tip

All defaults and tag names can be customized using the With* options. See Configuration Options for more details.

Field Name Mapping

By default, envcfg will search for environment variables using multiple naming patterns until a match is found. Use WithDisableFallback to restrict matching to only the env tag value.

For example:

os.Setenv("DATABASEURL",  "value") // Matches struct field
os.Setenv("DATABASE_URL", "value") // Matches snake-case
os.Setenv("DB_URL",      "value") // Matches json tag
os.Setenv("DATA_SOURCE", "value") // Matches yaml tag
os.Setenv("CUSTOM_URL",  "value") // Matches env tag

type Config struct {
    DatabaseURL string `json:"db_url" yaml:"data_source" env:"custom_url"`
}

Tip

All environment variable matching is case insensitive.

Nested Field Prefix Matching

envcfg supports three strategies for matching environment variable prefixes to struct fields: prefix, exact, and best:

type Config struct {
    Database struct {
        Host string // prefix (default) - only matches DATABASE_HOST
        Port int `match:"exact"` // exact - only matches PORT
        Name string `match:"best"` // best - tries DATABASE_NAME, then NAME
    }
}

Note

The matching strategy can be set globally with WithExactMatch or WithBestMatch or per-field using the match tag option.

Functions

  • Parse - Parse environment variables into a struct pointer
  • MustParse - Same as Parse, but panics on error
  • ParseAs - Parse environment variables into a specific type
  • MustParseAs - Same as ParseAs, but panics on error

Important

envcfg only parses exported fields.

Configuration Options

Components

Tag Description
WithParser Overrides the default parser
WithMatcher Overrides the default matcher
WithLoader Overrides the default loader
WithCustomOpts Passes arbitrary options to the above user-implemented components

Tags

Tag Description Default
WithTagName Tag name for environment variables env
WithDelimiterTag Tag name for delimiter delim
WithSeparatorTag Tag name for separator sep
WithDecodeUnsetTag Tag name for decoding unset environment variables decodeunset
WithDefaultTag Tag name for default values default
WithExpandTag Tag name for expandable variables expand
WithFileTag Tag name for file variables file
WithNotEmptyTag Tag name for not empty variables notEmpty
WithRequiredTag Tag name for required variables required
WithIgnoreTag Tag name for ignored variables ignore
WithMatchTag Tag name for match strategy match
WithInitTag Tag name for initialization strategy init

Walker

Tag Description Default
WithDelimiter Sets the default delimiter for array and map values ,
WithSeparator Sets the default separator for map key-value pairs :
WithDecodeUnset Enables decoding unset environment variables by default false
WithInitNever Sets the initialization strategy to never never
WithInitAlways Sets the initialization strategy to always always

Default Parser

Tag Description
WithTypeParser Sets a custom type parser
WithTypeParsers Sets custom type parsers
WithKindParser Sets a custom kind parser
WithKindParsers Sets custom kind parsers

Default Matcher

Tag Description Default
WithExactMatch Sets exact match strategy default strategy is prefix
WithBestMatch Sets best match strategy default strategy is prefix
WithDisableFallback Disables fallback to env tag value when no other matches are found false

Default Loader

Tag Description
WithSource Adds a custom source to the loader
WithEnvVarsSource Adds environment variables as a source
WithFileSource Adds a file as a source
WithOsEnvSource Adds the OS environment variables as a source
WithDefaults Adds default values to the loader
WithPrefix Combines WithTrimPrefix and WithHasPrefix
WithSuffix Combines WithTrimSuffix and WithHasSuffix
WithTransform Adds a transform function that modifies environment variable keys
WithTrimPrefix Removes a prefix from environment variable names
WithTrimSuffix Removes a suffix from environment variable names
WithFilter Adds a custom filter to the loader
WithHasPrefix Adds a prefix filter to the loader
WithHasSuffix Adds a suffix filter to the loader
WithHasMatch Adds a pattern filter to the loader

See GoDoc for more details.

About

Parse environment variables into Go structs with minimal boilerplate and first-class support for complex data structures

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages