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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Modeling each config source as a uniform function lets you compose lookup order without special-casing.
- 2A first-non-empty coalesce over an ordered chain gives clean precedence rules for free.
- 3Centralizing string-to-typed conversion behind one getter keeps parsing consistent and errors contained.
Related explainers
go
package streaming import ( "bufio"
Streaming NDJSON logs over HTTP in Go
http-streaming
channels
select
Advanced
10 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
go
package api import ( "crypto/sha256"
ETag conditional requests in Gin
http-caching
etag
conditional-requests
Intermediate
6 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
go
func (w *Watcher) resetDebounce(d time.Duration) { if !w.timer.Stop() { select { case <-w.timer.C:
Debouncing a stream of events in Go
debounce
timers
channels
Advanced
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/layered-config-resolution-in-go-explained-go-2619/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.