Help us shape the future of Go! Take the 2026 Go Developer Survey

config

package
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package config loads typed application configuration from environment variables and .env files.

Values are resolved with this precedence, highest first: the process environment, .env.<APP_ENV>.local, .env.local (skipped when APP_ENV=test), .env.<APP_ENV>, .env. Structs are filled with Fill using `env` and `default` struct tags.

LoadSource builds the Source the app reads from (app.Source), Load fills a typed struct from it, Secret keeps sensitive values out of logs and output, and Key parses APP_KEY and derives purpose keys from it.

See https://github.com/AlexGalhardo/vukem/blob/main/docs/configuration.md.

Index

Examples

Constants

View Source
const MinKeyLen = 32

MinKeyLen is the minimum APP_KEY length in bytes.

Variables

View Source
var ErrKeyMissing = errors.New("config: APP_KEY is not set (run `vukem key:generate`)")

ErrKeyMissing is returned by ParseKey when APP_KEY is empty. Outside production an app boots without a key, and every key-derived feature fails with it.

Functions

func Fill

func Fill(dst any, src Lookuper) error

Fill sets the exported fields of the struct pointed to by dst from src.

A field is read from the key in its `env` tag, falling back to its `default` tag. Struct fields without an `env` tag are filled recursively. Supported kinds: string, bool, ints, uints, floats, time.Duration, []string (comma-separated), *url.URL, Secret and any encoding.TextUnmarshaler. All conversion errors are returned together.

func GenerateKey

func GenerateKey() string

GenerateKey returns a new random APP_KEY value ("base64:..." of 32 bytes).

func Load

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

Load returns a T filled from src. See Fill.

Example
package main

import (
	"fmt"
	"time"

	"github.com/AlexGalhardo/vukem/config"
)

type MailConfig struct {
	Host     string        `env:"MAIL_HOST"     default:"localhost"`
	Port     int           `env:"MAIL_PORT"     default:"1025"`
	Timeout  time.Duration `env:"MAIL_TIMEOUT"  default:"10s"`
	Password config.Secret `env:"MAIL_PASSWORD"`
}

func main() {
	// Apps pass app.Source, loaded from .env files and the process
	// environment.
	src := config.MapSource(map[string]string{
		"MAIL_HOST":     "smtp.example.com",
		"MAIL_PASSWORD": "hunter2",
	})

	cfg, err := config.Load[MailConfig](src)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(cfg.Host, cfg.Port, cfg.Timeout)
	fmt.Println(cfg.Password, cfg.Password.Reveal() == "hunter2")
}
Output:
smtp.example.com 1025 10s
[redacted] true

func LookupErr added in v0.28.0

func LookupErr(src Lookuper, key string) (string, bool, error)

LookupErr reads key from src like Lookup, and also returns the error of an "@file:" process variable whose file cannot be read when src is a *Source (Lookup then reports the key set and empty). Code that reads configuration outside Load and Fill uses it to fail closed.

Types

type Entry

type Entry struct {
	Key   string
	Value string
	// Expand reports whether ${VAR} references in Value must be expanded.
	// Single-quoted values are literal.
	Expand bool
}

Entry is one KEY=VALUE pair parsed from a .env file.

func ParseEnv

func ParseEnv(r io.Reader) ([]Entry, error)

ParseEnv parses .env syntax: KEY=VALUE lines, optional "export " prefix, # comments, single-quoted literals and double-quoted values with escapes (which may span lines).

Example
package main

import (
	"fmt"
	"strings"

	"github.com/AlexGalhardo/vukem/config"
)

func main() {
	entries, err := config.ParseEnv(strings.NewReader("# app\nAPP_NAME=Shop\nexport APP_DEBUG=true\n"))
	if err != nil {
		fmt.Println(err)
		return
	}

	for _, e := range entries {
		fmt.Printf("%s=%s\n", e.Key, e.Value)
	}
}
Output:
APP_NAME=Shop
APP_DEBUG=true

type Env

type Env string

Env is the application environment (APP_ENV).

const (
	Development Env = "development"
	Production  Env = "production"
	Test        Env = "test"
)

Known environments.

type Key

type Key struct {
	// contains filtered or unexported fields
}

Key is the decoded application key (APP_KEY). Never use it directly for cryptography: derive a purpose-specific key with Derive.

func ParseKey

func ParseKey(s Secret) (Key, error)

ParseKey decodes an APP_KEY in the form "base64:<std base64>" (the prefix is optional) and enforces MinKeyLen.

func (Key) Derive

func (k Key) Derive(purpose string, n int) []byte

Derive returns an n-byte key for purpose using HKDF-SHA256, so cookies, sessions and encryption never share key material. It panics on a zero Key: deriving from no key material would yield a public, constant key. Check IsZero (or use App.DeriveKey) to fail with an error instead.

func (Key) IsZero added in v0.24.0

func (k Key) IsZero() bool

IsZero reports whether k holds no key (APP_KEY unset).

type Lookuper

type Lookuper interface {
	Lookup(key string) (string, bool)
}

Lookuper resolves configuration keys. *Source implements it.

type Secret

type Secret struct {
	// contains filtered or unexported fields
}

Secret holds a sensitive value. Every formatting path (fmt, encoding/json, log/slog) prints "[redacted]"; use Reveal to read the value.

func NewSecret

func NewSecret(v string) Secret

NewSecret wraps v.

func (Secret) GoString

func (Secret) GoString() string

GoString implements fmt.GoStringer so %#v does not leak the value.

func (Secret) IsZero

func (s Secret) IsZero() bool

IsZero reports whether the secret is empty.

func (Secret) LogValue

func (Secret) LogValue() slog.Value

LogValue implements slog.LogValuer.

func (Secret) MarshalJSON

func (Secret) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (Secret) MarshalText

func (Secret) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (Secret) Reveal

func (s Secret) Reveal() string

Reveal returns the underlying value. Call it only where the value is used.

func (Secret) String

func (Secret) String() string

String implements fmt.Stringer.

type Source

type Source struct {
	// contains filtered or unexported fields
}

Source is a resolved set of configuration values.

func LoadSource

func LoadSource(
	fsys fs.FS,
	getenv func(string) (string, bool),
	readFile func(string) ([]byte, error),
) (*Source, error)

LoadSource reads .env files from fsys and merges them with the process environment provided by getenv (use os.LookupEnv in production code). readFile resolves "@file:" values, in .env files and in the process environment; nil disables them. A referenced file must hold at most 1 MiB.

func MapSource

func MapSource(m map[string]string) *Source

MapSource builds a Source from a map, typically in tests.

func (*Source) Env

func (s *Source) Env() Env

Env returns the resolved application environment.

func (*Source) EnvSet added in v0.24.0

func (s *Source) EnvSet() bool

EnvSet reports whether APP_ENV was given explicitly (process environment, .env files or the map) with a non-empty value; Env then does not fall back to development.

func (*Source) Get

func (s *Source) Get(key string) string

Get returns the value for key or "" when unset.

func (*Source) Keys

func (s *Source) Keys() []string

Keys returns the sorted keys of values defined in .env files or the map.

func (*Source) Lookup

func (s *Source) Lookup(key string) (string, bool)

Lookup returns the value for key and whether it is set. The process environment wins over .env files. A process variable set to "@file:<path>" is read from that file (Docker/Kubernetes secrets), like a .env value; when the file cannot be read, Lookup reports the key set with an empty value, and Load and Fill return the error.

Jump to

Keyboard shortcuts

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