env

package module
v0.4.8 Latest Latest
Warning

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

Go to latest
Published: Nov 18, 2025 License: MIT Imports: 13 Imported by: 0

README

env

Credit

This repo is a heavily modified version of env by https://github.com/caarlos0 . Also major portions we adapted from github.com/joho/godotenv.

env utility functions

This repo provides some simple utilities for dealing with environment variables. There are some basic functions that are simple wrappers to the "os" package's env functions. These include:

err   = env.Set("KEY", "secret_key")
err   = env.Unset("KEY")
value = env.Get("OTHER_KEY")
value = env.GetOr("OTHER_KEY", "value returned if OTHER_KEY does not exist")
value = env.MustGet("KEY")  // panics if KEY does not exist

Parse environment vars into a struct

A much more powerful approach is to populate an annotated struct with values from the environment.

Take the following example:

type ClientConfig struct {
	Endpoint                  []string      `env:"ENDPOINT" required:"true"`
	HealthCheck               bool          `env:"HEALTH_CHECK" envDefault:"true"`
	HealthCheckTimeout        time.Duration `env:"HEALTH_CHECK_TIMEOUT" envDefault:"1s"`
}

This anotated struct can then be populated with the appropiate environment variables but using the following command:

	cfg := ClientConfig{}
	err := env.Parse(&cfg)

Using a prefix

If the struct you are populating is part of a library you may want to have parse the same struct but with different values. You can do this by using a prefix when parsing.

	cfg := ClientConfig{}
	err := env.ParseWithPrefix(&cfg, "CLIENT2_")

In this case the parser would look for the environment variables CLIENT2_ENDPOINT, CLIENT2_HEALTH_CHECK, etc.

Note: Prefixes must end with an underscore (_). If you provide a prefix without a trailing underscore, Parse will return an error.

Supported types and defaults

The environment variables are Parsed to go into the appropiate types (or an err is thrown if it can not do so). This sames you from writing a some basic validations on envirnment varaibles.

The library has built-in support for the following types:

  • string
  • int
  • uint
  • int64
  • bool
  • float32
  • float64
  • time.Duration
  • url.URL
  • []string
  • []int
  • []bool
  • []float32
  • []float64
  • []time.Duration
  • []url.URL
Optional tags

The required tag will cause an error if the environment variable does not exist: `env:"ENDPOINT" required:"true"`

The envDefault tag will allow you to provide a default value to use if the environment variable does not exist: `env:"HEALTH_CHECK" envDefault:"true"`

When assigning to a slice type the "," is used to seperate fields. You can override this with the envSeparator:":" tag to use some other character.

Advanced Features

Context-aware panics

Use MustGetWithContext for better error messages when required variables are missing:

apiBase := env.MustGetWithContext("WALLET_TRANSACTION_API", "generating wallet URIs")
// Panics with: "required env var WALLET_TRANSACTION_API missing (needed for: generating wallet URIs)"
Test helpers

The package provides convenient functions for managing environment variables in tests:

func TestConfig(t *testing.T) {
    // Automatically restores or removes the variable after the test
    env.SetForTest(t, "WALLET_TRANSACTION_API", "https://test.com")

    // Test code here
    // Cleanup happens automatically via t.Cleanup()
}

func TestWithoutEnv(t *testing.T) {
    // Temporarily removes a variable and restores it after test
    env.UnsetForTest(t, "OPTIONAL_CONFIG")

    // Test code that expects variable to not exist
}
Configuration validation

Validate that all required environment variables are set before parsing:

// Check required vars without parsing values
if err := env.ValidateRequired(&Config{}, ""); err != nil {
    log.Fatalf("Missing required configuration: %v", err)
}

// Now safe to parse
cfg := &Config{}
env.Parse(&cfg)
Environment variable discovery

Get information about all environment variables that a struct uses:

// Get all variables (required and optional)
vars, _ := env.GetAllVars(&Config{}, "")
for _, v := range vars {
    fmt.Printf("%s: %s (required: %v, default: %s)\n",
        v.Name, v.Type, v.Required, v.Default)
}

// Get only required variables
required, _ := env.GetRequiredVars(&Config{}, "")
fmt.Println("Required vars:", required)

This is useful for:

  • Generating documentation
  • Creating example .env files
  • Debugging configuration issues
  • Validating deployment environments
Debug logging

Enable debug logging to see what environment variables are being read:

// Enable debug logging
env.EnableDebugLogging(log.Printf)

cfg := &Config{}
env.Parse(&cfg)
// Logs: "env: DB_CONNECTION = postgres://... (field: Config.Database)"

// Disable debug logging
env.EnableDebugLogging(nil)

This is particularly useful for:

  • Debugging configuration issues in production
  • Understanding what values are being loaded
  • Troubleshooting environment variable naming
Better error messages

Parse errors now include field context for easier debugging:

type Config struct {
    Connection string `env:"DB_CONNECTION" required:"true"`
}

err := env.Parse(&Config{})
// Error: "field 'Connection' in Config: env var DB_CONNECTION was missing and is required"

Documentation

Overview

Package env provides utilities for working with environment variables and loading configuration from .env files.

This package offers three main areas of functionality:

1. Simple environment variable access with type conversion 2. Struct-based configuration parsing using struct tags 3. Loading and parsing of .env files

Basic Usage

Get environment variables with automatic type conversion:

port, err := env.GetInt("PORT")
if err != nil {
	port = env.GetOrInt("PORT", 8080) // with default
}

// Or panic if missing/invalid
dbHost := env.MustGet("DATABASE_HOST")

Struct-based Configuration

Parse environment variables into structs using tags:

type Config struct {
	Host string `env:"HOST" envDefault:"localhost"`
	Port int    `env:"PORT" envDefault:"8080"`
	Debug bool  `env:"DEBUG"`
}

var cfg Config
if err := env.Parse(&cfg); err != nil {
	log.Fatal(err)
}

File Loading

Load environment variables from .env files:

// Load from .env file
err := env.Load()
if err != nil {
	log.Fatal(err)
}

// Load from specific files
err = env.Load("config.env", "local.env")

Supported Types

The package supports automatic conversion for:

  • bool, int, uint, int64, uint64, float32, float64
  • time.Duration (using time.ParseDuration format)
  • *url.URL (using url.ParseRequestURI)
  • []string and other slice types (comma-separated by default)
  • Any type implementing encoding.TextUnmarshaler

Struct Tags

When using Parse functions, the following struct tags are supported:

  • env:"VAR_NAME" - specifies the environment variable name
  • envDefault:"value" - provides a default value if the variable is not set
  • required:"true" - makes the field required (parsing fails if missing)
  • envSeparator:";" - custom separator for slice types (default is comma)
  • envExpand:"true" - enables variable expansion using os.ExpandEnv

Error Handling

Functions come in three variants for different error handling approaches:

  • Get*() functions return (value, error)
  • GetOr*() functions return value with a fallback default
  • MustGet*() functions panic if the variable is missing or invalid

Index

Examples

Constants

View Source
const (
	DecimalBase = 10
	Int32Bits   = 32
	Int64Bits   = 64
	Float32Bits = 32
	Float64Bits = 64
)

Constants for parsing operations (shared with util.go)

Variables

View Source
var (
	// ErrNotAStructPtr is returned if you pass something that is not a pointer to a
	// Struct to Parse
	ErrNotAStructPtr = errors.New("expected a pointer to a Struct")
	// ErrUnsupportedType if the struct field type is not supported by env
	ErrUnsupportedType = errors.New("type is not supported")
	// ErrUnsupportedSliceType if the slice element type is not supported by env
	ErrUnsupportedSliceType = errors.New("unsupported slice type")
)
View Source
var (
	// OnEnvVarSet is an optional convenience callback, such as for logging purposes.
	// If not nil, it's called after successfully setting the given field from the given value.
	OnEnvVarSet func(reflect.StructField, string)
	// DebugLogger is an optional function for logging configuration parsing details.
	// If not nil, it's called with debug messages during Parse operations.
	// Use EnableDebugLogging to set this conveniently.
	DebugLogger func(format string, args ...interface{})
)
View Source
var (
	ParseBool = func(s string) (bool, error) {
		return strconv.ParseBool(s)
	}
	ParseInt = func(s string) (int, error) {
		v, err := strconv.ParseInt(s, DecimalBase, Int32Bits)
		return int(v), err
	}
	ParseUint = func(s string) (uint, error) {
		v, err := strconv.ParseUint(s, DecimalBase, Int32Bits)
		return uint(v), err
	}
	ParseFloat32 = func(s string) (float32, error) {
		v, err := strconv.ParseFloat(s, Float32Bits)
		return float32(v), err
	}
	ParseFloat64 = func(s string) (float64, error) {
		return strconv.ParseFloat(s, Float64Bits)
	}
	ParseInt64 = func(s string) (int64, error) {
		return strconv.ParseInt(s, DecimalBase, Int64Bits)
	}
	ParseUint64 = func(s string) (uint64, error) {
		return strconv.ParseUint(s, DecimalBase, Int64Bits)
	}
	ParseDuration = func(s string) (time.Duration, error) {
		return time.ParseDuration(s)
	}
	ParseURL = func(s string) (*url.URL, error) {
		return url.ParseRequestURI(s)
	}
)

Type-specific parser functions

Functions

func EnableDebugLogging added in v0.4.8

func EnableDebugLogging(logger func(format string, args ...interface{}))

EnableDebugLogging enables debug logging for configuration parsing. The provided logger function will be called with debug messages during Parse operations.

This is useful for debugging configuration issues, especially in production where you want to see what environment variables are being read and their values.

Example usage:

env.EnableDebugLogging(log.Printf)
cfg := &Config{}
env.Parse(&cfg) // Will log each env var as it's read

To disable debug logging, call env.EnableDebugLogging(nil).

func Get added in v0.2.0

func Get(key string) string

Get retrieves the value of an environment variable. If the variable is not set, it returns an empty string.

This is a simple wrapper around os.Getenv for consistency with other functions in this package.

Example
package main

import (
	"fmt"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	os.Setenv("HOME", "/home/user")
	fmt.Println(env.Get("HOME"))
	fmt.Println(env.Get("NONEXISTENT"))
}
Output:

/home/user

func GetBool added in v0.2.6

func GetBool(key string) (bool, error)

GetBool retrieves an environment variable and parses it as a boolean. It accepts values like "true", "false", "1", "0", "t", "f", "T", "F", "TRUE", "FALSE" (case-insensitive). Returns the parsed boolean value and any parsing error.

Example
package main

import (
	"fmt"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	os.Setenv("DEBUG", "true")
	os.Setenv("VERBOSE", "1")
	os.Setenv("QUIET", "false")

	debug, _ := env.GetBool("DEBUG")
	verbose, _ := env.GetBool("VERBOSE")
	quiet, _ := env.GetBool("QUIET")

	fmt.Println("Debug:", debug)
	fmt.Println("Verbose:", verbose)
	fmt.Println("Quiet:", quiet)
}
Output:

Debug: true
Verbose: true
Quiet: false

func GetDuration added in v0.4.0

func GetDuration(key string) (time.Duration, error)

GetDuration retrieves an environment variable and parses it as a time.Duration. It accepts duration strings like "5s", "2m30s", "1h", "300ms", etc. See time.ParseDuration for the complete format specification. Returns the parsed duration value and any parsing error.

Example
package main

import (
	"fmt"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	os.Setenv("TIMEOUT", "30s")
	os.Setenv("INTERVAL", "5m30s")

	timeout, _ := env.GetDuration("TIMEOUT")
	interval, _ := env.GetDuration("INTERVAL")

	fmt.Println("Timeout:", timeout)
	fmt.Println("Interval:", interval)
}
Output:

Timeout: 30s
Interval: 5m30s

func GetFloat32 added in v0.2.7

func GetFloat32(key string) (float32, error)

GetFloat32 retrieves an environment variable and parses it as a 32-bit floating point number. It accepts decimal numbers in standard or scientific notation. Returns the parsed float32 value and any parsing error.

func GetFloat64 added in v0.4.0

func GetFloat64(key string) (float64, error)

GetFloat64 retrieves an environment variable and parses it as a 64-bit floating point number. It accepts decimal numbers in standard or scientific notation. Returns the parsed float64 value and any parsing error.

func GetInt added in v0.2.6

func GetInt(key string) (int, error)

GetInt retrieves an environment variable and parses it as a signed integer. It accepts decimal integers that fit in the int type (platform-dependent size). Returns the parsed integer value and any parsing error.

Example
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	os.Setenv("PORT", "8080")
	os.Setenv("INVALID_PORT", "not-a-number")

	port, err := env.GetInt("PORT")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Port:", port)

	_, err = env.GetInt("INVALID_PORT")
	fmt.Println("Error:", err != nil)
}
Output:

Port: 8080
Error: true

func GetInt64 added in v0.4.0

func GetInt64(key string) (int64, error)

GetInt64 retrieves an environment variable and parses it as a 64-bit signed integer. It accepts decimal integers in the range -9223372036854775808 to 9223372036854775807. Returns the parsed int64 value and any parsing error.

func GetOr added in v0.2.0

func GetOr(key, defaultValue string) string

GetOr retrieves the value of an environment variable. If the variable is not set, it returns the provided default value.

This function distinguishes between unset variables and variables set to empty strings.

Example
package main

import (
	"fmt"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	os.Setenv("PORT", "8080")
	fmt.Println(env.GetOr("PORT", "3000"))
	fmt.Println(env.GetOr("MISSING_PORT", "3000"))
}
Output:

8080
3000

func GetOrBool added in v0.2.6

func GetOrBool(key string, defaultValue bool) bool

GetOrBool retrieves an environment variable and parses it as a boolean. If the variable is not set or parsing fails, it returns the default value.

func GetOrDuration added in v0.4.0

func GetOrDuration(key string, defaultValue string) time.Duration

GetOrDuration retrieves an environment variable and parses it as a time.Duration. If the variable is not set or parsing fails, it parses and returns the default value. The default value must be a valid duration string, or the function will panic.

Note: This function takes a string default value (unlike other GetOr* functions) to maintain backwards compatibility with existing APIs.

func GetOrFloat32 added in v0.2.7

func GetOrFloat32(key string, defaultValue float32) float32

GetOrFloat32 retrieves an environment variable and parses it as a 32-bit floating point number. If the variable is not set or parsing fails, it returns the default value.

func GetOrFloat64 added in v0.4.0

func GetOrFloat64(key string, defaultValue float64) float64

GetOrFloat64 retrieves an environment variable and parses it as a 64-bit floating point number. If the variable is not set or parsing fails, it returns the default value.

func GetOrInt added in v0.2.6

func GetOrInt(key string, defaultValue int) int

GetOrInt retrieves an environment variable and parses it as a signed integer. If the variable is not set or parsing fails, it returns the default value.

Example
package main

import (
	"fmt"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	os.Setenv("PORT", "8080")
	fmt.Println("Existing:", env.GetOrInt("PORT", 3000))
	fmt.Println("Missing:", env.GetOrInt("MISSING_PORT", 3000))
	fmt.Println("Invalid:", env.GetOrInt("INVALID_PORT", 3000))
}
Output:

Existing: 8080
Missing: 3000
Invalid: 3000

func GetOrInt64 added in v0.4.0

func GetOrInt64(key string, defaultValue int64) int64

GetOrInt64 retrieves an environment variable and parses it as a 64-bit signed integer. If the variable is not set or parsing fails, it returns the default value.

func GetOrParsed added in v0.4.6

func GetOrParsed[T any](key string, defaultValue T, parser Parser[T]) T

GetOrParsed retrieves an environment variable and parses it using the provided parser function. If the environment variable is not set or parsing fails, it returns the default value.

This function never returns an error; it falls back to the default value on any failure.

func GetOrUint added in v0.2.6

func GetOrUint(key string, defaultValue uint) uint

GetOrUint retrieves an environment variable and parses it as an unsigned integer. If the variable is not set or parsing fails, it returns the default value.

func GetOrUint64 added in v0.4.0

func GetOrUint64(key string, defaultValue uint64) uint64

GetOrUint64 retrieves an environment variable and parses it as a 64-bit unsigned integer. If the variable is not set or parsing fails, it returns the default value.

func GetOrUrl added in v0.4.0

func GetOrUrl(key string, defaultValue string) *url.URL

GetOrUrl retrieves an environment variable and parses it as a URL. If the variable is not set or parsing fails, it parses and returns the default value. The default value must be a valid URL string, or the function will panic.

Note: This function takes a string default value (unlike other GetOr* functions) to maintain backwards compatibility with existing APIs.

func GetParsed added in v0.4.6

func GetParsed[T any](key string, parser Parser[T]) (T, error)

GetParsed retrieves an environment variable and parses it using the provided parser function. It returns the parsed value and any parsing error. If the environment variable is not set, the parser receives an empty string.

This is a generic function that can be used with any type that has a corresponding parser. For common types, use the specific Get* functions which are more convenient.

func GetRequiredVars added in v0.4.8

func GetRequiredVars(v interface{}, prefix string) ([]string, error)

GetRequiredVars returns the names of all required environment variables that would be read when parsing the given struct.

The prefix parameter is prepended to all environment variable names.

This function is useful for validating that all required variables are set before attempting to parse the configuration.

Example usage:

required := env.GetRequiredVars(&Config{}, "")
for _, name := range required {
    if _, ok := os.LookupEnv(name); !ok {
        log.Fatalf("Required environment variable %s is not set", name)
    }
}

func GetUint added in v0.2.6

func GetUint(key string) (uint, error)

GetUint retrieves an environment variable and parses it as an unsigned integer. It accepts non-negative decimal integers that fit in the uint type (platform-dependent size). Returns the parsed unsigned integer value and any parsing error.

func GetUint64 added in v0.4.0

func GetUint64(key string) (uint64, error)

GetUint64 retrieves an environment variable and parses it as a 64-bit unsigned integer. It accepts non-negative decimal integers in the range 0 to 18446744073709551615. Returns the parsed uint64 value and any parsing error.

func GetUrl added in v0.4.0

func GetUrl(key string) (*url.URL, error)

GetUrl retrieves an environment variable and parses it as a URL. It accepts absolute URLs and parses them using url.ParseRequestURI. Returns the parsed *url.URL value and any parsing error.

func Load added in v0.2.5

func Load(filenames ...string) (err error)

Load reads environment variables from .env files and sets them in the current process. If no filenames are provided, it defaults to loading ".env" from the current directory.

Multiple files can be loaded in order:

err := env.Load("base.env", "local.env")

Important: Load will NOT override environment variables that are already set. This allows .env files to provide defaults while respecting existing environment configuration. Use Overload if you need to override existing variables.

The function returns an error if any file cannot be read or parsed. Call this early in your program, typically in main().

Example
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	// Create a temporary .env file
	envContent := `# Database configuration
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=myapp

# Application settings
DEBUG=true
LOG_LEVEL=info`

	err := os.WriteFile(".env", []byte(envContent), 0600)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(".env")

	// Load the .env file
	err = env.Load()
	if err != nil {
		log.Fatal(err)
	}

	// Access the loaded variables
	fmt.Println("Database Host:", env.Get("DATABASE_HOST"))
	fmt.Println("Database Port:", env.GetOrInt("DATABASE_PORT", 0))
	fmt.Println("Debug Mode:", env.GetOrBool("DEBUG", false))
}
Output:

Database Host: localhost
Database Port: 5432
Debug Mode: true

func Marshal added in v0.2.5

func Marshal(envMap map[string]string) (string, error)

Marshal converts a map of environment variables to .env file format. It returns a string with KEY="VALUE" pairs, one per line, with keys sorted alphabetically and values properly escaped with backslashes.

This function does not write to any file; use Write to save the output to disk.

Example
package main

import (
	"fmt"
	"log"

	"github.com/lindenlab/env"
)

func main() {
	envMap := map[string]string{
		"DATABASE_URL": "postgres://localhost/myapp",
		"DEBUG":        "true",
		"PORT":         "8080",
		"API_KEY":      "secret with spaces",
	}

	content, err := env.Marshal(envMap)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(content)
}
Output:

API_KEY="secret with spaces"
DATABASE_URL="postgres://localhost/myapp"
DEBUG="true"
PORT="8080"

func MustGet added in v0.2.0

func MustGet(key string) string

MustGet retrieves the value of an environment variable. If the variable is not set, it panics with a descriptive message.

Use this function when the environment variable is required for the application to function.

func MustGetBool added in v0.2.6

func MustGetBool(key string) bool

MustGetBool retrieves an environment variable and parses it as a boolean. If the variable is not set or parsing fails, it panics.

func MustGetDuration added in v0.4.0

func MustGetDuration(key string) time.Duration

MustGetDuration retrieves an environment variable and parses it as a time.Duration. If the variable is not set or parsing fails, it panics.

func MustGetFloat32 added in v0.2.7

func MustGetFloat32(key string) float32

MustGetFloat32 retrieves an environment variable and parses it as a 32-bit floating point number. If the variable is not set or parsing fails, it panics.

func MustGetFloat64 added in v0.4.0

func MustGetFloat64(key string) float64

MustGetFloat64 retrieves an environment variable and parses it as a 64-bit floating point number. If the variable is not set or parsing fails, it panics.

func MustGetInt added in v0.2.6

func MustGetInt(key string) int

MustGetInt retrieves an environment variable and parses it as a signed integer. If the variable is not set or parsing fails, it panics.

func MustGetInt64 added in v0.4.0

func MustGetInt64(key string) int64

MustGetInt64 retrieves an environment variable and parses it as a 64-bit signed integer. If the variable is not set or parsing fails, it panics.

func MustGetParsed added in v0.4.6

func MustGetParsed[T any](key string, parser Parser[T], typeName string) T

MustGetParsed retrieves an environment variable and parses it using the provided parser function. If the environment variable is not set or parsing fails, it panics with a descriptive message.

The typeName parameter is used in panic messages to identify the expected type. Use this function when the environment variable is required for the application to function.

func MustGetUint added in v0.2.6

func MustGetUint(key string) uint

MustGetUint retrieves an environment variable and parses it as an unsigned integer. If the variable is not set or parsing fails, it panics.

func MustGetUint64 added in v0.4.0

func MustGetUint64(key string) uint64

MustGetUint64 retrieves an environment variable and parses it as a 64-bit unsigned integer. If the variable is not set or parsing fails, it panics.

func MustGetUrl added in v0.4.0

func MustGetUrl(key string) *url.URL

MustGetUrl retrieves an environment variable and parses it as a URL. If the variable is not set or parsing fails, it panics.

func MustGetWithContext added in v0.4.8

func MustGetWithContext(key, context string) string

MustGetWithContext retrieves the value of an environment variable with additional context. If the variable is not set, it panics with a descriptive message that includes the context.

The context parameter should describe why this variable is needed, making errors more helpful. For example: "generating wallet URIs" or "connecting to database".

Use this function when the environment variable is required and you want to provide additional context in error messages.

func MustLoad added in v0.2.7

func MustLoad(filenames ...string)

MustLoad reads environment variables from .env files and sets them in the current process. If no filenames are provided, it defaults to loading ".env" from the current directory.

This function behaves exactly like Load, except it panics on any error instead of returning it. Use this when .env file loading is critical for your application to function.

Multiple files can be loaded in order:

env.MustLoad("base.env", "local.env")

Like Load, this will NOT override environment variables that are already set.

func MustOverload added in v0.2.7

func MustOverload(filenames ...string)

MustOverload reads environment variables from .env files and sets them in the current process, overriding any existing environment variables. If no filenames are provided, it defaults to loading ".env" from the current directory.

This function behaves exactly like Overload, except it panics on any error instead of returning it. Use this when .env file loading is critical and should override existing configuration.

Multiple files can be loaded in order:

env.MustOverload("base.env", "production.env")

func Overload added in v0.2.5

func Overload(filenames ...string) (err error)

Overload reads environment variables from .env files and sets them in the current process, overriding any existing environment variables. If no filenames are provided, it defaults to loading ".env" from the current directory.

Unlike Load, this function WILL override environment variables that are already set. Use this when you want .env files to take precedence over existing environment configuration.

Multiple files can be loaded in order:

err := env.Overload("base.env", "production.env")

The function returns an error if any file cannot be read or parsed.

func Parse

func Parse(v interface{}) error

Parse populates a struct's fields from environment variables. The struct fields must be tagged with `env:"VAR_NAME"` to specify which environment variable to read.

Supported struct tags:

  • env:"VAR_NAME" - specifies the environment variable name (required)
  • envDefault:"value" - default value if the environment variable is not set
  • required:"true" - makes the field required (causes error if missing)
  • envSeparator:"," - separator for slice types (default is comma)
  • envExpand:"true" - enables variable expansion using os.ExpandEnv

The function supports nested structs and pointers to structs. It returns an error if required fields are missing or if type conversion fails.

Example
type config struct {
	Home         string `env:"HOME"`
	Port         int    `env:"PORT" envDefault:"3000"`
	IsProduction bool   `env:"PRODUCTION"`
}
os.Setenv("HOME", "/tmp/fakehome")
cfg := config{}
_ = Parse(&cfg)
fmt.Println(cfg)
Output:

{/tmp/fakehome 3000 false}
Example
package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/lindenlab/env"
)

func main() {
	// Set up environment variables
	os.Setenv("HOME", "/tmp/fakehome")
	os.Setenv("PORT", "8080")
	os.Setenv("DEBUG", "true")
	os.Setenv("TAGS", "web,api,database")
	os.Setenv("TIMEOUT", "30s")

	type Config struct {
		Home     string        `env:"HOME"`
		Port     int           `env:"PORT" envDefault:"3000"`
		Debug    bool          `env:"DEBUG"`
		Tags     []string      `env:"TAGS" envSeparator:","`
		Timeout  time.Duration `env:"TIMEOUT" envDefault:"10s"`
		Version  string        `env:"VERSION" envDefault:"1.0.0"`
		Required string        `env:"REQUIRED_VAR" required:"true"`
	}

	// This will fail because REQUIRED_VAR is not set
	var cfg Config
	err := env.Parse(&cfg)
	if err != nil {
		fmt.Println("Error:", err != nil)
	}

	// Set the required variable and try again
	os.Setenv("REQUIRED_VAR", "important-value")
	err = env.Parse(&cfg)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Home: %s\n", cfg.Home)
	fmt.Printf("Port: %d\n", cfg.Port)
	fmt.Printf("Debug: %t\n", cfg.Debug)
	fmt.Printf("Tags: %v\n", cfg.Tags)
	fmt.Printf("Timeout: %v\n", cfg.Timeout)
	fmt.Printf("Version: %s\n", cfg.Version)
	fmt.Printf("Required: %s\n", cfg.Required)
}
Output:

Error: true
Home: /tmp/fakehome
Port: 8080
Debug: true
Tags: [web api database]
Timeout: 30s
Version: 1.0.0
Required: important-value

func ParseIO added in v0.2.5

func ParseIO(r io.Reader) (envMap map[string]string, err error)

ParseIO reads environment variables from an io.Reader in .env format. It parses the content and returns a map of key-value pairs.

This function supports the standard .env file format including:

  • Comments (lines starting with #)
  • Quoted values (both single and double quotes)
  • Variable expansion (${VAR} and $VAR syntax)
  • Multiline values
  • Both KEY=value and KEY: value formats

It does not set any environment variables; it only parses and returns the data.

func ParseWithFuncs

func ParseWithFuncs(v interface{}, funcMap CustomParsers) error

ParseWithFuncs populates a struct's fields from environment variables, using custom parsing functions for specific types.

This allows you to handle types that aren't supported by default. The funcMap parameter maps reflect.Type values to ParserFunc implementations.

See Parse for details on supported struct tags and behavior.

func ParseWithPrefix

func ParseWithPrefix(v interface{}, prefix string) error

ParseWithPrefix populates a struct's fields from environment variables with a prefix. This is useful for loading different configurations for the same struct type.

For example, with prefix "CLIENT2_", a field tagged `env:"ENDPOINT"` will read from the environment variable "CLIENT2_ENDPOINT".

The prefix must end with an underscore if it's not empty, otherwise an error is returned.

See Parse for details on supported struct tags and behavior.

Example
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	// Set up environment variables with prefixes
	os.Setenv("CLIENT1_HOST", "api.example.com")
	os.Setenv("CLIENT1_PORT", "443")
	os.Setenv("CLIENT2_HOST", "internal.example.com")
	os.Setenv("CLIENT2_PORT", "8080")

	type ClientConfig struct {
		Host string `env:"HOST" envDefault:"localhost"`
		Port int    `env:"PORT" envDefault:"80"`
	}

	var client1, client2 ClientConfig

	err := env.ParseWithPrefix(&client1, "CLIENT1_")
	if err != nil {
		log.Fatal(err)
	}
	err = env.ParseWithPrefix(&client2, "CLIENT2_")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Client 1: %s:%d\n", client1.Host, client1.Port)
	fmt.Printf("Client 2: %s:%d\n", client2.Host, client2.Port)
}
Output:

Client 1: api.example.com:443
Client 2: internal.example.com:8080

func ParseWithPrefixFuncs

func ParseWithPrefixFuncs(v interface{}, prefix string, funcMap CustomParsers) error

ParseWithPrefixFuncs populates a struct's fields from environment variables with both a prefix and custom parsing functions.

This combines the functionality of ParseWithPrefix and ParseWithFuncs, allowing both prefixed variable names and custom type parsing.

The prefix must end with an underscore if it's not empty, otherwise an error is returned.

See Parse for details on supported struct tags and behavior.

func Read added in v0.2.5

func Read(filenames ...string) (envMap map[string]string, err error)

Read parses .env files and returns the key-value pairs as a map, without setting them as environment variables in the current process.

This is useful when you want to inspect or manipulate the values before applying them, or when you want to use the values in a different way. If no filenames are provided, it defaults to reading ".env" from the current directory.

Multiple files can be read, with later files overriding earlier ones:

envMap, err := env.Read("base.env", "local.env")
if err != nil {
	log.Fatal(err)
}
fmt.Printf("DATABASE_URL=%s\n", envMap["DATABASE_URL"])
Example
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/lindenlab/env"
)

func main() {
	// Create a temporary .env file
	envContent := `DATABASE_URL=postgres://localhost/myapp
REDIS_URL=redis://localhost:6379
API_KEY=secret123
DEBUG=true`

	err := os.WriteFile("config.env", []byte(envContent), 0600)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove("config.env")

	// Read the file without setting environment variables
	envMap, err := env.Read("config.env")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Database URL:", envMap["DATABASE_URL"])
	fmt.Println("Redis URL:", envMap["REDIS_URL"])
	fmt.Println("Debug:", envMap["DEBUG"])
}
Output:

Database URL: postgres://localhost/myapp
Redis URL: redis://localhost:6379
Debug: true

func Set added in v0.2.0

func Set(key, value string) error

Set sets an environment variable to the specified value. It returns an error if the operation fails.

This is a simple wrapper around os.Setenv for consistency with other functions in this package.

func SetForTest added in v0.4.8

func SetForTest(t TestHelper, key, value string) func()

SetForTest sets an environment variable for testing and automatically cleans it up. It returns a cleanup function that can be called manually, though cleanup is also registered with t.Cleanup() if t is non-nil.

If the environment variable already exists, it will be restored to its original value. If it doesn't exist, it will be removed during cleanup.

Example usage:

func TestConfig(t *testing.T) {
    cleanup := env.SetForTest(t, "WALLET_TRANSACTION_API", "https://test.com")
    defer cleanup() // Optional: cleanup is also registered with t.Cleanup()
    // test code
}

func Unmarshal added in v0.2.5

func Unmarshal(str string) (envMap map[string]string, err error)

Unmarshal parses environment variables from a string in .env format. It returns a map of key-value pairs without setting any environment variables.

This is a convenience function that wraps ParseIO with a strings.NewReader. See ParseIO for details on the supported .env file format.

func Unset added in v0.2.0

func Unset(key string) error

Unset removes an environment variable. It returns an error if the operation fails.

This is a simple wrapper around os.Unsetenv for consistency with other functions in this package.

func UnsetForTest added in v0.4.8

func UnsetForTest(t TestHelper, key string) func()

UnsetForTest removes an environment variable for testing and automatically restores it. It returns a cleanup function that can be called manually, though cleanup is also registered with t.Cleanup() if t is non-nil.

If the environment variable exists, it will be restored to its original value during cleanup.

Example usage:

func TestWithoutEnv(t *testing.T) {
    cleanup := env.UnsetForTest(t, "OPTIONAL_CONFIG")
    defer cleanup()
    // test code that expects the variable to not exist
}

func ValidateRequired added in v0.4.8

func ValidateRequired(v interface{}, prefix string) error

ValidateRequired checks if all required environment variables for the given struct are set. It does not parse the values, only checks for their existence.

This is useful for validating configuration at startup before attempting to parse, which can provide clearer error messages.

Example usage:

if err := env.ValidateRequired(&Config{}, ""); err != nil {
    log.Fatalf("Configuration validation failed: %v", err)
}
// Now safe to parse
env.Parse(&cfg)

func Write added in v0.2.5

func Write(envMap map[string]string, filename string) error

Write serializes a map of environment variables to a .env file. The output file will contain KEY="VALUE" pairs, one per line, with keys sorted alphabetically and values properly escaped.

This function will create or overwrite the specified file.

Types

type CustomParsers

type CustomParsers map[reflect.Type]ParserFunc

CustomParsers maps Go types to custom parsing functions. It allows you to provide custom logic for parsing environment variables into specific types that aren't supported by default.

The key is the reflect.Type of the target type, and the value is a ParserFunc that knows how to convert a string to that type.

type ParseErrors added in v0.4.6

type ParseErrors []error

ParseErrors represents multiple errors that occurred during parsing

func (ParseErrors) Error added in v0.4.6

func (pe ParseErrors) Error() string

Error implements the error interface for ParseErrors

type Parser added in v0.4.6

type Parser[T any] func(string) (T, error)

Parser is a function type that converts a string value to type T. It is used by the generic parsing functions to provide type-safe conversion from environment variable string values.

type ParserFunc

type ParserFunc func(v string) (interface{}, error)

ParserFunc defines the signature of a custom parsing function. It takes a string value from an environment variable and returns the parsed value as an interface{} and any parsing error.

The returned value should be of the type that the parser is designed to handle.

type TestHelper added in v0.4.8

type TestHelper interface {
	Helper()
	Cleanup(func())
}

TestHelper is an interface that represents a testing object (typically *testing.T or *testing.B). It provides the minimal interface needed for test helper functions.

type VarInfo added in v0.4.8

type VarInfo struct {
	// Name is the full environment variable name (including any prefix)
	Name string
	// FieldName is the struct field name
	FieldName string
	// FieldPath is the full path to the field (for nested structs)
	FieldPath string
	// Required indicates if the environment variable is required
	Required bool
	// Default is the default value if the environment variable is not set
	Default string
	// Type is the Go type of the field
	Type string
	// HasDefault indicates if a default value is specified
	HasDefault bool
}

VarInfo contains information about an environment variable used by a struct field.

func GetAllVars added in v0.4.8

func GetAllVars(v interface{}, prefix string) ([]VarInfo, error)

GetAllVars returns information about all environment variables that would be read when parsing the given struct. This includes both required and optional variables.

The prefix parameter is prepended to all environment variable names.

This function is useful for:

  • Generating documentation
  • Creating example .env files
  • Debugging configuration issues
  • Validating that all expected variables are set

Example usage:

vars := env.GetAllVars(&Config{}, "")
for _, v := range vars {
    fmt.Printf("%s: %s (required: %v, default: %s)\n",
        v.Name, v.Type, v.Required, v.Default)
}

Jump to

Keyboard shortcuts

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