go 60 lines · 8 steps

Layered config resolution in Go

A function-based source chain resolves config from flags, environment, then a file, with typed fallbacks.

Explained by highlit
1package config
2 
3import (
4 "os"
5 "strconv"
6 "time"
7)
8 
9type Config struct {
10 ListenAddr string
11 DatabaseURL string
12 MaxConns int
13 ReadTimeout time.Duration
14 Debug bool
15}
16 
17type source func(key string) (string, bool)
18 
19func fromEnv(key string) (string, bool) {
20 return os.LookupEnv(key)
21}
22 
23func fromMap(m map[string]string) source {
24 return func(key string) (string, bool) {
25 v, ok := m[key]
26 return v, ok
27 }
28}
29 
30func coalesce(key string, sources ...source) string {
31 for _, s := range sources {
32 if v, ok := s(key); ok && v != "" {
33 return v
34 }
35 }
36 return ""
37}
38 
39func Load(flags, file map[string]string) Config {
40 chain := []source{fromMap(flags), fromEnv, fromMap(file)}
41 
42 get := func(key, fallback string) string {
43 if v := coalesce(key, chain...); v != "" {
44 return v
45 }
46 return fallback
47 }
48 
49 maxConns, _ := strconv.Atoi(get("MAX_CONNS", "25"))
50 readTimeout, _ := time.ParseDuration(get("READ_TIMEOUT", "15s"))
51 debug, _ := strconv.ParseBool(get("DEBUG", "false"))
52 
53 return Config{
54 ListenAddr: get("LISTEN_ADDR", ":8080"),
55 DatabaseURL: get("DATABASE_URL", "postgres://localhost/app"),
56 MaxConns: maxConns,
57 ReadTimeout: readTimeout,
58 Debug: debug,
59 }
60}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Modeling each config source as a uniform function lets you compose lookup order without special-casing.
  2. 2A first-non-empty coalesce over an ordered chain gives clean precedence rules for free.
  3. 3Centralizing string-to-typed conversion behind one getter keeps parsing consistent and errors contained.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Layered config resolution in Go — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code