Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

go-simpler.org/env

Package Overview
Dependencies
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

go-simpler.org/env

Go Modules
Version
v0.12.0
Version published
Created
Source

logo

🔍 Load environment variables into a config struct

awesome-go checks pkg.go.dev goreportcard codecov

📌 About

This package is made for apps that store config in environment variables. Its purpose is to replace fragmented os.Getenv calls in main.go with a single struct definition, which simplifies config management and improves code readability.

🚀 Features

📦 Install

Go 1.20+

go get go-simpler.org/env

📋 Usage

Load is the main function of the package. It loads environment variables into the given struct.

The struct fields must have the env:"VAR" struct tag, where VAR is the name of the corresponding environment variable. Unexported fields are ignored.

os.Setenv("PORT", "8080")

var cfg struct {
    Port int `env:"PORT"`
}
if err := env.Load(&cfg, nil); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.Port) // 8080

Supported types

  • int (any kind)
  • float (any kind)
  • bool
  • string
  • time.Duration
  • encoding.TextUnmarshaler
  • slices of any type above
  • nested structs of any depth

See the strconv.Parse* functions for the parsing rules. User-defined types can be used by implementing the encoding.TextUnmarshaler interface.

Nested structs

Nested struct of any depth level are supported, allowing grouping of related environment variables.

os.Setenv("DB_HOST", "localhost")
os.Setenv("DB_PORT", "5432")

var cfg struct {
    DB struct {
        Host string `env:"DB_HOST"`
        Port int    `env:"DB_PORT"`
    }
}
if err := env.Load(&cfg, nil); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.DB.Host) // localhost
fmt.Println(cfg.DB.Port) // 5432

If a nested struct has the optional env:"PREFIX" tag, the environment variables declared by its fields are prefixed with PREFIX.

os.Setenv("DB_HOST", "localhost")
os.Setenv("DB_PORT", "5432")

var cfg struct {
    DB struct {
        Host string `env:"HOST"`
        Port int    `env:"PORT"`
    } `env:"DB_"`
}
if err := env.Load(&cfg, nil); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.DB.Host) // localhost
fmt.Println(cfg.DB.Port) // 5432

Default values

Default values can be specified using the default:"VALUE" struct tag.

os.Unsetenv("PORT")

var cfg struct {
    Port int `env:"PORT" default:"8080"`
}
if err := env.Load(&cfg, nil); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.Port) // 8080

Required

Use the required option to mark an environment variable as required. If it is not set, an error of type NotSetError is returned.

os.Unsetenv("PORT")

var cfg struct {
    Port int `env:"PORT,required"`
}
if err := env.Load(&cfg, nil); err != nil {
    var notSetErr *env.NotSetError
    if errors.As(err, &notSetErr) {
        fmt.Println(notSetErr) // env: PORT is required but not set
    }
}

Expand

Use the expand option to automatically expand the value of an environment variable using os.Expand.

os.Setenv("PORT", "8080")
os.Setenv("ADDR", "localhost:${PORT}")

var cfg struct {
    Addr string `env:"ADDR,expand"`
}
if err := env.Load(&cfg, nil); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.Addr) // localhost:8080

Slice separator

Space is the default separator used to parse slice values. It can be changed with Options.SliceSep.

os.Setenv("PORTS", "8080,8081,8082")

var cfg struct {
    Ports []int `env:"PORTS"`
}
if err := env.Load(&cfg, &env.Options{SliceSep: ","}); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.Ports) // [8080 8081 8082]

Name separator

By default, environment variable names are concatenated from nested struct tags as is. If Options.NameSep is not empty, it is used as the separator.

os.Setenv("DB_HOST", "localhost")
os.Setenv("DB_PORT", "5432")

var cfg struct {
    DB struct {
        Host string `env:"HOST"`
        Port int    `env:"PORT"`
    } `env:"DB"`
}
if err := env.Load(&cfg, &env.Options{NameSep: "_"}); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.DB.Host) // localhost
fmt.Println(cfg.DB.Port) // 5432

Source

By default, Load retrieves environment variables directly from OS. To use a different source, pass an implementation of the Source interface via Options.Source.

type Source interface {
    LookupEnv(key string) (value string, ok bool)
}

Here's an example of using Map, a Source implementation useful in tests.

m := env.Map{"PORT": "8080"}

var cfg struct {
    Port int `env:"PORT"`
}
if err := env.Load(&cfg, &env.Options{Source: m}); err != nil {
    fmt.Println(err)
}

fmt.Println(cfg.Port) // 8080

Usage message

The Usage function prints a usage message documenting all defined environment variables. An optional usage string can be added to environment variables with the usage:"STRING" struct tag.

os.Unsetenv("DB_HOST")
os.Unsetenv("DB_PORT")

var cfg struct {
    DB struct {
        Host string `env:"DB_HOST,required" usage:"database host"`
        Port int    `env:"DB_PORT,required" usage:"database port"`
    }
    HTTPPort int `env:"HTTP_PORT" default:"8080" usage:"http server port"`
}
if err := env.Load(&cfg, nil); err != nil {
    fmt.Println(err)
    fmt.Println("Usage:")
    env.Usage(&cfg, os.Stdout, nil)
}
Usage:
  DB_HOST    string  required      database host
  DB_PORT    int     required      database port
  HTTP_PORT  int     default 8080  http server port

The format of the message can be customized by implementing the Usage([]env.Var, io.Writer, *env.Options) method.

type Config struct{ ... }

func (Config) Usage(vars []env.Var, w io.Writer, opts *env.Options) {
    for v := range vars {
        // write to w.
    }
}

FAQs

Package last updated on 02 May 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts