go 55 lines · 8 steps

Loading typed config from environment variables in Go

A Load function fills a Config struct from environment variables, applying defaults and parsing each value into its proper type.

Explained by highlit
1package config
2 
3import (
4 "fmt"
5 "os"
6 "strconv"
7 "strings"
8 "time"
9)
10 
11type Config struct {
12 Host string `env:"HOST"`
13 Port int `env:"PORT"`
14 Debug bool `env:"DEBUG"`
15 ReadTimeout time.Duration `env:"READ_TIMEOUT"`
16 AllowedHosts []string `env:"ALLOWED_HOSTS"`
17}
18 
19func Load() (*Config, error) {
20 cfg := &Config{
21 Host: "0.0.0.0",
22 Port: 8080,
23 ReadTimeout: 15 * time.Second,
24 }
25 
26 if v, ok := os.LookupEnv("HOST"); ok {
27 cfg.Host = v
28 }
29 if v, ok := os.LookupEnv("PORT"); ok {
30 port, err := strconv.Atoi(v)
31 if err != nil {
32 return nil, fmt.Errorf("PORT: %w", err)
33 }
34 cfg.Port = port
35 }
36 if v, ok := os.LookupEnv("DEBUG"); ok {
37 debug, err := strconv.ParseBool(v)
38 if err != nil {
39 return nil, fmt.Errorf("DEBUG: %w", err)
40 }
41 cfg.Debug = debug
42 }
43 if v, ok := os.LookupEnv("READ_TIMEOUT"); ok {
44 d, err := time.ParseDuration(v)
45 if err != nil {
46 return nil, fmt.Errorf("READ_TIMEOUT: %w", err)
47 }
48 cfg.ReadTimeout = d
49 }
50 if v, ok := os.LookupEnv("ALLOWED_HOSTS"); ok {
51 cfg.AllowedHosts = strings.Split(v, ",")
52 }
53 
54 return cfg, nil
55}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Seed a config struct with sensible defaults, then let environment variables override only what's present.
  2. 2os.LookupEnv distinguishes an unset variable from an empty one, so absent vars keep their defaults untouched.
  3. 3Wrapping parse errors with the variable name turns a vague failure into an immediately actionable message.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Loading typed config from environment variables in Go — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code