Skip to content
/ env Public

Strongly-typed environment variables for Go with safe defaults, app env helpers, and zero-ceremony configuration.

License

Notifications You must be signed in to change notification settings

goforj/env

Repository files navigation

goforj/env logo

Typed environment variables for Go - safe defaults, app env helpers, and zero-ceremony configuration.

Go Reference License: MIT Go Test Go version Latest tag Go Report Card

env provides strongly-typed access to environment variables with predictable fallbacks. Eliminate string parsing, centralize app environment checks, and keep configuration boring. Designed to feel native to Go - and invisible when things are working.

Features

  • 🔐 Strongly typed getters - int, bool, float, duration, slices, maps
  • 🧯 Safe fallbacks - never panic, never accidentally empty
  • 🌎 Application environment helpers - dev, local, prod
  • 🧩 Minimal dependencies - Pure Go, lightweight, minimal surface area
  • 🧭 Framework-agnostic - works with any Go app
  • 📐 Enum validation - constrain values with allowed sets
  • 🧼 Predictable behavior - no magic, no global state surprises
  • 🧱 Composable building block - ideal for config structs and startup wiring

Why env?

Accessing environment variables in Go often leads to:

  • Repeated parsing logic
  • Unsafe string conversions
  • Inconsistent defaults
  • Scattered app environment checks

env solves this by providing typed accessors with fallbacks, so configuration stays boring and predictable.

Features

  • Strongly typed getters (int, bool, duration, slices, maps)
  • Safe fallbacks (never panic, never empty by accident)
  • App environment helpers (dev, local, prod)
  • Zero dependencies
  • Framework-agnostic

Installation

go get github.com/goforj/env

Quickstart

package main

import (
	"log"
	"time"

	"github.com/goforj/env"
)

func init() {
	if err := env.LoadEnvFileIfExists(); err != nil {
		log.Fatalf("load env: %v", err)
	}
}

func main() {
    addr := env.Get("ADDR", "127.0.0.1:8080")
    debug := env.GetBool("DEBUG", "false")
    timeout := env.GetDuration("HTTP_TIMEOUT", "5s")
    
    env.Dump(addr, debug, timeout)
    // #string "127.0.0.1:8080"
    // #bool false
    // #time.Duration 5s
    
    env.Dump("container?", env.IsContainer())
    // #string "container?"
    // #bool false
}

Full kitchen-sink example

See examples/kitchensink/main.go for a runnable program that exercises almost every helper (env loading, typed getters, must-getters, runtime + container detection, and the env.Dump wrapper) with deterministic godump output.

Environment file loading

This package uses github.com/joho/godotenv for .env file loading.

It is intentionally composed into the runtime detection and APP_ENV model rather than reimplemented.

Runnable examples

Every function has a corresponding runnable example under ./examples.

These examples are generated directly from the documentation blocks of each function, ensuring the docs and code never drift. These are the same examples you see here in the README and GoDoc.

An automated test executes every example to verify it builds and runs successfully.

This guarantees all examples are valid, up-to-date, and remain functional as the API evolves.

Container detection at a glance

Check True when Notes
IsDocker /.dockerenv or Docker cgroup markers Generic Docker container
IsDockerInDocker /.dockerenv and docker.sock Inner DinD container
IsDockerHost docker.sock present, no container cgroups Host or DinD outer acting as host
IsContainer Any common container signals (Docker, containerd, kube env/cgroup) General container detection
IsKubernetes KUBERNETES_SERVICE_HOST or kubepods cgroup Inside a Kubernetes pod

Index

Group Functions
Application environment GetAppEnv IsAppEnv IsAppEnvDev IsAppEnvLocal IsAppEnvLocalOrStaging IsAppEnvProduction IsAppEnvStaging IsAppEnvTesting IsAppEnvTestingOrLocal
Container detection IsContainer IsDocker IsDockerHost IsDockerInDocker IsHostEnvironment IsKubernetes
Debugging Dump
Environment loading IsEnvLoaded LoadEnvFileIfExists
Runtime Arch IsBSD IsContainerOS IsLinux IsMac IsUnix IsWindows OS
Typed getters Get GetBool GetDuration GetEnum GetFloat GetInt GetInt64 GetMap GetSlice GetUint GetUint64 MustGet MustGetBool MustGetInt

Application environment

GetAppEnv · readonly

GetAppEnv returns the current APP_ENV (empty string if unset).

Example: simple retrieval

_ = os.Setenv("APP_ENV", "staging")
env.Dump(env.GetAppEnv())

// #string "staging"

IsAppEnv · readonly

IsAppEnv checks if APP_ENV matches any of the provided environments.

Example: match any allowed environment

_ = os.Setenv("APP_ENV", "staging")
env.Dump(env.IsAppEnv(env.Production, env.Staging))

// #bool true

Example: unmatched environment

_ = os.Setenv("APP_ENV", "local")
env.Dump(env.IsAppEnv(env.Production, env.Staging))

// #bool false

IsAppEnvDev · readonly

IsAppEnvDev checks if APP_ENV is "dev".

_ = os.Setenv("APP_ENV", env.Dev)
env.Dump(env.IsAppEnvDev())

// #bool true

IsAppEnvLocal · readonly

IsAppEnvLocal checks if APP_ENV is "local".

_ = os.Setenv("APP_ENV", env.Local)
env.Dump(env.IsAppEnvLocal())

// #bool true

IsAppEnvLocalOrStaging · readonly

IsAppEnvLocalOrStaging checks if APP_ENV is either "local" or "staging".

_ = os.Setenv("APP_ENV", env.Local)
env.Dump(env.IsAppEnvLocalOrStaging())

// #bool true

IsAppEnvProduction · readonly

IsAppEnvProduction checks if APP_ENV is "production".

_ = os.Setenv("APP_ENV", env.Production)
env.Dump(env.IsAppEnvProduction())

// #bool true

IsAppEnvStaging · readonly

IsAppEnvStaging checks if APP_ENV is "staging".

_ = os.Setenv("APP_ENV", env.Staging)
env.Dump(env.IsAppEnvStaging())

// #bool true

IsAppEnvTesting · readonly

IsAppEnvTesting reports whether APP_ENV is "testing" or the process looks like go test.

Example: APP_ENV explicitly testing

_ = os.Setenv("APP_ENV", env.Testing)
env.Dump(env.IsAppEnvTesting())

// #bool true

Example: no test markers

_ = os.Unsetenv("APP_ENV")
env.Dump(env.IsAppEnvTesting())

// #bool false (outside of test binaries)

IsAppEnvTestingOrLocal · readonly

IsAppEnvTestingOrLocal checks if APP_ENV is "testing" or "local".

_ = os.Setenv("APP_ENV", env.Testing)
env.Dump(env.IsAppEnvTestingOrLocal())

// #bool true

Container detection

IsContainer · readonly

IsContainer detects common container runtimes (Docker, containerd, Kubernetes, Podman).

Example: host vs container

env.Dump(env.IsContainer())

// #bool true  (inside most containers)
// #bool false (on bare-metal/VM hosts)

IsDocker · readonly

IsDocker reports whether the current process is running in a Docker container.

Example: typical host

env.Dump(env.IsDocker())

// #bool false (unless inside Docker)

IsDockerHost · readonly

IsDockerHost reports whether this container behaves like a Docker host.

env.Dump(env.IsDockerHost())

// #bool true  (when acting as Docker host)
// #bool false (for normal containers/hosts)

IsDockerInDocker · readonly

IsDockerInDocker reports whether we are inside a Docker-in-Docker environment.

env.Dump(env.IsDockerInDocker())

// #bool true  (inside DinD containers)
// #bool false (on hosts or non-DinD containers)

IsHostEnvironment · readonly

IsHostEnvironment reports whether the process is running outside any container or orchestrated runtime.

env.Dump(env.IsHostEnvironment())

// #bool true  (on bare-metal/VM hosts)
// #bool false (inside containers)

IsKubernetes · readonly

IsKubernetes reports whether the process is running inside Kubernetes.

env.Dump(env.IsKubernetes())

// #bool true  (inside Kubernetes pods)
// #bool false (elsewhere)

Debugging

Dump · readonly

Dump is a convenience function that calls godump.Dump.

Example: integers

nums := []int{1, 2, 3}
env.Dump(nums)

// #[]int [
//   0 => 1 #int
//   1 => 2 #int
//   2 => 3 #int
// ]

Example: multiple values

env.Dump("status", map[string]int{"ok": 1, "fail": 0})

// #string "status"
// #map[string]int [
//   "fail" => 0 #int
//   "ok"   => 1 #int
// ]

Environment loading

IsEnvLoaded · readonly

IsEnvLoaded reports whether LoadEnvFileIfExists was executed in this process.

env.Dump(env.IsEnvLoaded())

// #bool true  (after LoadEnvFileIfExists)
// #bool false (otherwise)

LoadEnvFileIfExists · mutates-process-env

LoadEnvFileIfExists loads .env/.env.testing/.env.host when present.

Example: test-specific env file

tmp, _ := os.MkdirTemp("", "envdoc")
_ = os.WriteFile(filepath.Join(tmp, ".env.testing"), []byte("PORT=9090\nAPP_DEBUG=0"), 0o644)
_ = os.Chdir(tmp)
_ = os.Setenv("APP_ENV", env.Testing)

_ = env.LoadEnvFileIfExists()
env.Dump(os.Getenv("PORT"))

// #string "9090"

Example: default .env on a host

_ = os.WriteFile(".env", []byte("SERVICE=api\nAPP_DEBUG=3"), 0o644)
_ = env.LoadEnvFileIfExists()
env.Dump(os.Getenv("SERVICE"))

// #string "api"

Runtime

Arch · readonly

Arch returns the CPU architecture the binary is running on.

Example: print GOARCH

env.Dump(env.Arch())

// #string "amd64"
// #string "arm64"

IsBSD · readonly

IsBSD reports whether the runtime OS is any BSD variant.

env.Dump(env.IsBSD())

// #bool true  (on BSD variants)
// #bool false (elsewhere)

IsContainerOS · readonly

IsContainerOS reports whether this OS is typically used as a container base.

env.Dump(env.IsContainerOS())

// #bool true  (on Linux)
// #bool false (on macOS/Windows)

IsLinux · readonly

IsLinux reports whether the runtime OS is Linux.

env.Dump(env.IsLinux())

// #bool true  (on Linux)
// #bool false (on other OSes)

IsMac · readonly

IsMac reports whether the runtime OS is macOS (Darwin).

env.Dump(env.IsMac())

// #bool true  (on macOS)
// #bool false (elsewhere)

IsUnix · readonly

IsUnix reports whether the OS is Unix-like.

env.Dump(env.IsUnix())

// #bool true  (on Unix-like OSes)
// #bool false (e.g., on Windows or Plan 9)

IsWindows · readonly

IsWindows reports whether the runtime OS is Windows.

env.Dump(env.IsWindows())

// #bool true  (on Windows)
// #bool false (elsewhere)

OS · readonly

OS returns the current operating system identifier.

Example: inspect GOOS

env.Dump(env.OS())

// #string "linux"   (on Linux)
// #string "darwin"  (on macOS)
// #string "windows" (on Windows)

Typed getters

Get · readonly

Get returns the environment variable for key or fallback when empty.

Example: fallback when unset

os.Unsetenv("DB_HOST")
host := env.Get("DB_HOST", "localhost")
env.Dump(host)

// #string "localhost"

Example: prefer existing value

_ = os.Setenv("DB_HOST", "db.internal")
host = env.Get("DB_HOST", "localhost")
env.Dump(host)

// #string "db.internal"

GetBool · readonly

GetBool parses a boolean from an environment variable or fallback string.

Example: numeric truthy

_ = os.Setenv("DEBUG", "1")
debug := env.GetBool("DEBUG", "false")
env.Dump(debug)

// #bool true

Example: fallback string

os.Unsetenv("DEBUG")
debug = env.GetBool("DEBUG", "false")
env.Dump(debug)

// #bool false

GetDuration · readonly

GetDuration parses a Go duration string (e.g. "5s", "10m", "1h").

Example: override request timeout

_ = os.Setenv("HTTP_TIMEOUT", "30s")
timeout := env.GetDuration("HTTP_TIMEOUT", "5s")
env.Dump(timeout)

// #time.Duration 30s

Example: fallback when unset

os.Unsetenv("HTTP_TIMEOUT")
timeout = env.GetDuration("HTTP_TIMEOUT", "5s")
env.Dump(timeout)

// #time.Duration 5s

GetEnum · readonly

GetEnum ensures the environment variable's value is in the allowed list.

Example: accept only staged environments

_ = os.Setenv("APP_ENV", "prod")
appEnv := env.GetEnum("APP_ENV", "dev", []string{"dev", "staging", "prod"})
env.Dump(appEnv)

// #string "prod"

Example: fallback when unset

os.Unsetenv("APP_ENV")
appEnv = env.GetEnum("APP_ENV", "dev", []string{"dev", "staging", "prod"})
env.Dump(appEnv)

// #string "dev"

GetFloat · readonly

GetFloat parses a float64 from an environment variable or fallback string.

Example: override threshold

_ = os.Setenv("THRESHOLD", "0.82")
threshold := env.GetFloat("THRESHOLD", "0.75")
env.Dump(threshold)

// #float64 0.82

Example: fallback with decimal string

os.Unsetenv("THRESHOLD")
threshold = env.GetFloat("THRESHOLD", "0.75")
env.Dump(threshold)

// #float64 0.75

GetInt · readonly

GetInt parses an int from an environment variable or fallback string.

Example: fallback used

os.Unsetenv("PORT")
port := env.GetInt("PORT", "3000")
env.Dump(port)

// #int 3000

Example: env overrides fallback

_ = os.Setenv("PORT", "8080")
port = env.GetInt("PORT", "3000")
env.Dump(port)

// #int 8080

GetInt64 · readonly

GetInt64 parses an int64 from an environment variable or fallback string.

Example: parse large numbers safely

_ = os.Setenv("MAX_SIZE", "1048576")
size := env.GetInt64("MAX_SIZE", "512")
env.Dump(size)

// #int64 1048576

Example: fallback when unset

os.Unsetenv("MAX_SIZE")
size = env.GetInt64("MAX_SIZE", "512")
env.Dump(size)

// #int64 512

GetMap · readonly

GetMap parses key=value pairs separated by commas into a map.

Example: parse throttling config

_ = os.Setenv("LIMITS", "read=10, write=5, burst=20")
limits := env.GetMap("LIMITS", "")
env.Dump(limits)

// #map[string]string [
//  "burst" => "20" #string
//  "read"  => "10" #string
//  "write" => "5" #string
// ]

Example: returns empty map when unset or blank

os.Unsetenv("LIMITS")
limits = env.GetMap("LIMITS", "")
env.Dump(limits)

// #map[string]string []

GetSlice · readonly

GetSlice splits a comma-separated string into a []string with trimming.

Example: trimmed addresses

_ = os.Setenv("PEERS", "10.0.0.1, 10.0.0.2")
peers := env.GetSlice("PEERS", "")
env.Dump(peers)

// #[]string [
//  0 => "10.0.0.1" #string
//  1 => "10.0.0.2" #string
// ]

Example: empty becomes empty slice

os.Unsetenv("PEERS")
peers = env.GetSlice("PEERS", "")
env.Dump(peers)

// #[]string []

GetUint · readonly

GetUint parses a uint from an environment variable or fallback string.

Example: defaults to fallback when missing

os.Unsetenv("WORKERS")
workers := env.GetUint("WORKERS", "4")
env.Dump(workers)

// #uint 4

Example: uses provided unsigned value

_ = os.Setenv("WORKERS", "16")
workers = env.GetUint("WORKERS", "4")
env.Dump(workers)

// #uint 16

GetUint64 · readonly

GetUint64 parses a uint64 from an environment variable or fallback string.

Example: high range values

_ = os.Setenv("MAX_ITEMS", "5000")
maxItems := env.GetUint64("MAX_ITEMS", "100")
env.Dump(maxItems)

// #uint64 5000

Example: fallback when unset

os.Unsetenv("MAX_ITEMS")
maxItems = env.GetUint64("MAX_ITEMS", "100")
env.Dump(maxItems)

// #uint64 100

MustGet · panic

MustGet returns the value of key or panics if missing/empty.

Example: required secret

_ = os.Setenv("API_SECRET", "s3cr3t")
secret := env.MustGet("API_SECRET")
env.Dump(secret)

// #string "s3cr3t"

Example: panic on missing value

os.Unsetenv("API_SECRET")
secret = env.MustGet("API_SECRET") // panics: env variable missing: API_SECRET

MustGetBool · panic

MustGetBool panics if missing or invalid.

Example: gate features explicitly

_ = os.Setenv("FEATURE_ENABLED", "true")
enabled := env.MustGetBool("FEATURE_ENABLED")
env.Dump(enabled)

// #bool true

Example: panic on invalid value

_ = os.Setenv("FEATURE_ENABLED", "maybe")
_ = env.MustGetBool("FEATURE_ENABLED") // panics when parsing

MustGetInt · panic

MustGetInt panics if the value is missing or not an int.

Example: ensure numeric port

_ = os.Setenv("PORT", "8080")
port := env.MustGetInt("PORT")
env.Dump(port)

// #int 8080

Example: panic on bad value

_ = os.Setenv("PORT", "not-a-number")
_ = env.MustGetInt("PORT") // panics when parsing

Philosophy

env is part of the GoForj toolchain - a collection of focused, composable packages designed to make building Go applications satisfying.

No magic. No globals. No surprises.

License

MIT

About

Strongly-typed environment variables for Go with safe defaults, app env helpers, and zero-ceremony configuration.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages