Getting Started
Quick installation and basic usage
This page walks you through installing envconfig and wiring up your first environment-based configuration in a Go application. envconfig maps environment variables directly onto a Go struct using field tags, eliminating the boilerplate of repeated os.Getenv calls and manual type conversions. By the end of this tutorial you will have a working configuration struct that reads from your environment and is ready to extend. If you are building any Go service that needs to respect twelve-factor app principles, this is your starting point.
Before you begin, make sure you have the following:
- Go 1.18 or later installed and your
GOPATHconfigured correctly - A Go module initialized in your project (
go mod init <module-name>) - Basic familiarity with Go structs and struct tags
- Access to a terminal where you can set environment variables
- Add envconfig to your module:
go get github.com/kelseyhightower/envconfig - Define a struct with
envconfigfield tags. - Call
envconfig.Processto populate the struct from your environment. - Use the resulting values in your application.
The four steps above are everything you need for a working configuration. The sections below explain each one in detail.
Step 1 — Install envconfig
From your project root, run:
go get github.com/kelseyhightower/envconfig
This adds envconfig to your go.mod and downloads the source. Confirm the dependency was recorded:
grep envconfig go.mod
You should see a line starting with require github.com/kelseyhightower/envconfig.
Step 2 — Define your configuration struct
Create a struct whose fields represent each configuration value your application needs. Use the envconfig struct tag to map a field to a specific environment variable name. Fields without a tag are matched by their uppercased field name by default.
type Config struct {
Port int `envconfig:"PORT"`
Host string `envconfig:"HOST"`
Debug bool `envconfig:"DEBUG"`
LogLevel string `envconfig:"LOG_LEVEL"`
}
Keeping all configuration in one struct makes it easy to see every external dependency your application has at a glance.
Step 3 — Set environment variables
Before running your application, export the variables your struct expects:
export PORT=8080
export HOST=localhost
export DEBUG=true
export LOG_LEVEL=info
In production you would set these through your deployment platform (Docker, Kubernetes, systemd, etc.) rather than exporting them manually.
Step 4 — Process environment variables into the struct
Call envconfig.Process with a prefix and a pointer to your struct. The prefix is prepended to every variable name when envconfig looks up values, which prevents collisions when multiple services share an environment.
package main
import (
"fmt"
"log"
"github.com/kelseyhightower/envconfig"
)
type Config struct {
Port int `envconfig:"PORT"`
Host string `envconfig:"HOST"`
Debug bool `envconfig:"DEBUG"`
LogLevel string `envconfig:"LOG_LEVEL"`
}
func main() {
var cfg Config
err := envconfig.Process("MYAPP", &cfg)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Listening on %s:%d (debug=%v, log=%s)\n",
cfg.Host, cfg.Port, cfg.Debug, cfg.LogLevel)
}
With the prefix "MYAPP", envconfig looks for MYAPP_PORT, MYAPP_HOST, and so on. Update your exports to match:
export MYAPP_PORT=8080
export MYAPP_HOST=localhost
export MYAPP_DEBUG=true
export MYAPP_LOG_LEVEL=info
A successful run prints the resolved values, confirming your struct was populated correctly.
Basic configuration with a prefix
A complete minimal program that reads four variables and prints the result.
package main
import (
"fmt"
"log"
"github.com/kelseyhightower/envconfig"
)
type Config struct {
Port int `envconfig:"PORT"`
Host string `envconfig:"HOST"`
Debug bool `envconfig:"DEBUG"`
LogLevel string `envconfig:"LOG_LEVEL"`
}
func main() {
var cfg Config
if err := envconfig.Process("MYAPP", &cfg); err != nil {
log.Fatal(err)
}
fmt.Printf("host=%s port=%d debug=%v log_level=%s\n",
cfg.Host, cfg.Port, cfg.Debug, cfg.LogLevel)
}
Set variables and run:
export MYAPP_PORT=8080
export MYAPP_HOST=localhost
export MYAPP_DEBUG=true
export MYAPP_LOG_LEVEL=info
go run main.go
Expected output:
host=localhost port=8080 debug=true log_level=info
Using default values
Annotate fields with default to provide fallback values when an environment variable is not set. This is useful for local development where you may not want to export every variable.
type Config struct {
Port int `envconfig:"PORT" default:"3000"`
Host string `envconfig:"HOST" default:"0.0.0.0"`
Debug bool `envconfig:"DEBUG" default:"false"`
LogLevel string `envconfig:"LOG_LEVEL" default:"warn"`
}
Run without any exports:
go run main.go
Expected output:
host=0.0.0.0 port=3000 debug=false log_level=warn
Marking required variables
Use the required tag to make envconfig return an error if a variable is missing. This fails fast at startup instead of silently using a zero value.
type Config struct {
DatabaseURL string `envconfig:"DATABASE_URL" required:"true"`
Port int `envconfig:"PORT" default:"8080"`
}
If MYAPP_DATABASE_URL is not set, envconfig.Process returns:
required key MYAPP_DATABASE_URL missing value
Variable is not being picked up
Symptom: A struct field stays at its zero value even though you exported the variable.
Likely cause: The environment variable name does not match the expected pattern. envconfig combines your prefix with the field name or envconfig tag value, separated by an underscore.
Fix: Double-check the full variable name. If your prefix is MYAPP and the tag is PORT, the expected variable is MYAPP_PORT. Run env | grep MYAPP to list what is actually set in your shell.
Type conversion error at startup
Symptom: envconfig.Process returns an error like envconfig.Process: assigning MYAPP_PORT to Port: converting 'abc' to type int.
Likely cause: The value of the environment variable cannot be parsed into the Go type declared on the struct field.
Fix: Verify the exported value is valid for the target type. For example, PORT must be a valid integer string (8080), and DEBUG must be true or false for a bool field.
Required variable error even though the variable is set
Symptom: You see required key MYAPP_FOO missing value but echo $MYAPP_FOO prints a value.
Likely cause: The variable was exported in a different shell session or sub-shell and is not present in the environment of the current process.
Fix: Export the variable in the same shell session where you run go run or go build. Alternatively, prefix the command inline: MYAPP_FOO=bar go run main.go.
go get cannot find the module
Symptom: go get fails with cannot find module providing package github.com/kelseyhightower/envconfig.
Likely cause: Your Go environment is in GOPATH mode rather than module mode, or there is a network/proxy issue.
Fix: Ensure your project has a go.mod file (go mod init <name> if not). If you are behind a corporate proxy, set GONOSUMCHECK or GOFLAGS appropriately, or use GOFLAGS=-mod=mod.