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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Seed a config struct with sensible defaults, then let environment variables override only what's present.
- 2os.LookupEnv distinguishes an unset variable from an empty one, so absent vars keep their defaults untouched.
- 3Wrapping parse errors with the variable name turns a vague failure into an immediately actionable message.
Related explainers
rust
use axum::{ extract::{FromRef, FromRequestParts}, http::{header, request::Parts, StatusCode}, RequestPartsExt,
How a JWT extractor works in Axum
jwt
authentication
extractors
Intermediate
8 steps
typescript
import { InjectionToken, inject, Provider, isDevMode } from '@angular/core'; import { WINDOW } from './window.token'; export interface AnalyticsConfig {
Layered config with an Angular InjectionToken
dependency-injection
configuration
factory-provider
Intermediate
8 steps
go
package server import ( "net/http"
Rate limiting HTTP handlers with a token bucket
rate-limiting
token-bucket
middleware
Advanced
7 steps
go
package middleware import ( "fmt"
How a panic-recovery middleware works in Gin
middleware
panic-recovery
error-reporting
Intermediate
8 steps
rust
#[derive(Deserialize)] pub struct CreateArticle { title: String, body: String,
Building a create endpoint in Axum
extractors
json-deserialization
sqlx
Intermediate
7 steps
go
func UploadDocument(c *gin.Context) { fileHeader, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "file is required"})
Handling multipart uploads in Gin
multipart-upload
validation
error-handling
Intermediate
9 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/loading-typed-config-from-environment-variables-in-go-explained-go-2493/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.