Skip to content

About

Typed .env file loader with reflection-based struct binding for Go. Zero-dependency Go stdlib-only library.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

go-envconfig

A small, zero-dependency Go library for loading typed configuration from .env-style files into structs, with real OS environment variables available as a fallback.

It has two parts:

  • A hand-written .env file parser (Parse) with no third-party dependencies — comments, blank lines, quoted and unquoted values.
  • A reflection-based struct loader (Load) that binds parsed values (and, as a fallback, real OS environment variables) onto struct fields using env:"KEY_NAME" tags, and reports every validation problem it finds in a single call instead of stopping at the first one.

Installation

go get github.com/kasapdev/go-envconfig

Usage

Given a .env file like this:

# .env
APP_NAME=widget-service
APP_PORT=8080
APP_DEBUG=true
APP_TAGS=api,internal,beta
package main

import (
	"fmt"
	"log"

	"github.com/kasapdev/go-envconfig"
)

type Config struct {
	Name  string   `env:"APP_NAME,required"`
	Port  int      `env:"APP_PORT,required"`
	Debug bool     `env:"APP_DEBUG"`
	Tags  []string `env:"APP_TAGS"`
}

func main() {
	var cfg Config
	if err := envconfig.Load(".env", &cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%+v\n", cfg)
	// {Name:widget-service Port:8080 Debug:true Tags:[api internal beta]}
}

Precedence: file values vs. OS environment variables

For each tagged field, Load resolves its value in this order:

  1. The parsed .env file is checked first.
  2. If the key is not present in the file, Load falls back to the real OS environment (os.Getenv).
  3. If the key is present in neither, the field is left at its zero value — unless the tag includes ,required, in which case it is recorded as a missing-field error.

This means a .env file can be used to override the OS environment during local development, while deployment environments that don't ship a .env file at all can still supply every value through real environment variables.

API

func Parse(path string) (map[string]string, error)

Reads a .env-style file and returns its key/value pairs as a map. Skips full-line comments (#...) and blank lines. Supports:

  • Double-quoted values, with \n, \t, \r, \", and \\ escapes processed.
  • Single-quoted values, used verbatim (no escape processing).
  • Unquoted values, trimmed of surrounding whitespace.

Parse does not touch the real process environment — it only returns the parsed map. It is exposed directly in case you want the raw key/value pairs without struct binding.

func Load(path string, target any) error

Parses the file at path and populates the exported fields of target (which must be a non-nil pointer to a struct) using env:"KEY_NAME" struct tags:

  • env:"KEY_NAME" — optional field.
  • env:"KEY_NAME,required" — the key must resolve to a value (from the file or the OS environment); otherwise it's reported as an error.

Supported field types: string, int, int64, bool, and []string (the raw value is split on commas, with each element trimmed of whitespace).

Load never stops at the first problem. It collects every missing required field and every type-conversion failure, then returns them all together as a single *MultiError. It returns nil if and only if no problems were found.

type MultiError struct { ... }

Implements error, and aggregates multiple underlying errors:

  • Error() string — renders one problem per line.
  • Unwrap() []error — supports errors.Is / errors.As per the Go 1.20+ multi-error convention.
  • Errors() []error — returns the individual errors.
  • Len() int — the number of aggregated errors.

Testing

go test ./...

License

MIT — see LICENSE.

About

Typed .env file loader with reflection-based struct binding for Go. Zero-dependency Go stdlib-only library.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages