Skip to main content

Configuration Management in Go

Created: May 8, 2026 3 min read

Introduction

Proper configuration management is essential for deploying applications across environments. This guide covers environment-based configuration, secrets management, and best practices. See Go Installation Guide, Go Ecosystem Overview, Go Best Practices for more context.

Core Concepts

Configuration Types

  • Environment Variables: Runtime configuration
  • Config Files: Structured configuration
  • Secrets: Sensitive credentials
  • Feature Flags: Runtime behavior control

Good: Environment-Based Configuration

Configuration Struct

package main

import (
	"os"
	"strconv"
)

// ✅ GOOD: Configuration struct
type Config struct {
	Port         int
	DatabaseURL  string
	LogLevel     string
	Environment  string
	JWTSecret    string
	APIKey       string
}

// ✅ GOOD: Load from environment
func LoadConfig() *Config {
	return &Config{
		Port:        getEnvInt("PORT", 8080),
		DatabaseURL: getEnv("DATABASE_URL", ""),
		LogLevel:    getEnv("LOG_LEVEL", "info"),
		Environment: getEnv("ENVIRONMENT", "development"),
		JWTSecret:   getEnv("JWT_SECRET", ""),
		APIKey:      getEnv("API_KEY", ""),
	}
}

func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

func getEnvInt(key string, defaultValue int) int {
	if value := os.Getenv(key); value != "" {
		if intVal, err := strconv.Atoi(value); err == nil {
			return intVal
		}
	}
	return defaultValue
}

// ✅ GOOD: Validate configuration
func (c *Config) Validate() error {
	if c.DatabaseURL == "" {
		return fmt.Errorf("DATABASE_URL is required")
	}
	if c.JWTSecret == "" {
		return fmt.Errorf("JWT_SECRET is required")
	}
	return nil
}

Good: Secrets Management

Using Environment Variables

// ✅ GOOD: Load secrets from environment
func LoadSecrets() *Secrets {
	return &Secrets{
		DatabasePassword: os.Getenv("DB_PASSWORD"),
		APIKey:          os.Getenv("API_KEY"),
		JWTSecret:       os.Getenv("JWT_SECRET"),
	}
}

// ❌ BAD: Hardcoded secrets
const (
	DatabasePassword = "password123"
	APIKey          = "sk_live_abc123"
)

Using .env Files

// ✅ GOOD: Load from .env file
import "github.com/joho/godotenv"

func init() {
	godotenv.Load()
}

// .env file
// DATABASE_URL=postgres://user:password@localhost/db
// JWT_SECRET=secret-key
// API_KEY=api-key

Good: Configuration Files

YAML Configuration

package main

import (
	"gopkg.in/yaml.v2"
	"io/ioutil"
)

// ✅ GOOD: YAML configuration
type AppConfig struct {
	Server struct {
		Port int    `yaml:"port"`
		Host string `yaml:"host"`
	} `yaml:"server"`
	Database struct {
		URL string `yaml:"url"`
	} `yaml:"database"`
}

func LoadConfigFromFile(filename string) (*AppConfig, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	var config AppConfig
	if err := yaml.Unmarshal(data, &config); err != nil {
		return nil, err
	}

	return &config, nil
}

Advanced Patterns

Feature Flags

// ✅ GOOD: Feature flags
type FeatureFlags struct {
	NewUI       bool
	BetaFeature bool
	Maintenance bool
}

func LoadFeatureFlags() *FeatureFlags {
	return &FeatureFlags{
		NewUI:       getEnvBool("FEATURE_NEW_UI", false),
		BetaFeature: getEnvBool("FEATURE_BETA", false),
		Maintenance: getEnvBool("MAINTENANCE_MODE", false),
	}
}

func getEnvBool(key string, defaultValue bool) bool {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}
	return value == "true" || value == "1"
}

Configuration Validation

// ✅ GOOD: Validate configuration
func (c *Config) Validate() error {
	if c.Port < 1 || c.Port > 65535 {
		return fmt.Errorf("invalid port: %d", c.Port)
	}

	if c.Environment != "dev" && c.Environment != "prod" {
		return fmt.Errorf("invalid environment: %s", c.Environment)
	}

	if c.DatabaseURL == "" {
		return fmt.Errorf("DATABASE_URL is required")
	}

	return nil
}

Best Practices

1. Use Environment Variables

// ✅ GOOD: Environment variables
port := os.Getenv("PORT")

// ❌ BAD: Hardcoded values
port := "8080"

2. Validate Configuration

// ✅ GOOD: Validate on startup
config := LoadConfig()
if err := config.Validate(); err != nil {
	log.Fatal(err)
}

// ❌ BAD: No validation
config := LoadConfig()

3. Use Secrets Management

// ✅ GOOD: Use secrets manager
secret := os.Getenv("API_KEY")

// ❌ BAD: Hardcoded secrets
secret := "sk_live_abc123"

Resources

Summary

Proper configuration management enables flexible deployment across environments. Use environment variables for configuration, validate on startup, and never hardcode secrets. Following these practices ensures secure, maintainable applications.

Comments

Share this article

Scan to read on mobile