Documentation Index Fetch the complete documentation index at: https://mnah05-boiler-go-21-79.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Boiler-Go uses environment variables for configuration with strong validation and fail-fast error handling. Configuration is managed in internal/config/config.go.
Configuration structure
All configuration is defined in the Config struct:
type Config struct {
// Server
AppPort string `env:"APP_PORT" envDefault:"8080"`
// Database
DatabaseURL string `env:"DATABASE_URL,required"`
// Redis / Asynq
RedisAddr string `env:"REDIS_ADDR,required"`
RedisPassword string `env:"REDIS_PASSWORD"`
RedisDB int `env:"REDIS_DB" envDefault:"0"`
// Timeouts
HealthCheckTimeout time . Duration `env:"HEALTH_CHECK_TIMEOUT" envDefault:"2s"`
APIShutdownTimeout time . Duration `env:"API_SHUTDOWN_TIMEOUT" envDefault:"10s"`
WorkerShutdownTimeout time . Duration `env:"WORKER_SHUTDOWN_TIMEOUT" envDefault:"30s"`
// Logging
LogOutput string `env:"LOG_OUTPUT" envDefault:"stdout"`
LogFile string `env:"LOG_FILE"`
}
Fields tagged with ,required must be provided. The application will fail to start if they’re missing.
Loading configuration
Configuration is loaded once using the singleton pattern:
var (
cfg * Config
once sync . Once
)
func Load ( logg zerolog . Logger ) * Config {
once . Do ( func () {
// Load .env file if present
if err := godotenv . Load (); err != nil {
logg . Info (). Msg ( "no .env file found (using system environment)" )
}
// Parse environment variables
c := Config {}
if err := env . Parse ( & c ); err != nil {
logg . Fatal (). Err ( err ). Msg ( "failed to load config" )
}
// Validate configuration
// ... validation logic ...
cfg = & c
})
return cfg
}
Load .env file
Attempts to load .env file from the current directory (optional)
Parse environment
Parses environment variables into the Config struct using struct tags
Validate values
Runs comprehensive validation on all configuration values
Store singleton
Stores the validated config for the application lifetime
Environment variables
Server configuration
HTTP server port. Must be between 1 and 65535.
Database configuration
PostgreSQL connection string. Must use postgres:// or postgresql:// scheme. DATABASE_URL = postgres://user:pass@localhost:5432/dbname
The URL is validated in internal/config/config.go:115-132: func validateDatabaseURL ( dbURL string ) error {
u , err := url . Parse ( dbURL )
if err != nil {
return fmt . Errorf ( "invalid URL format: %w " , err )
}
// Check scheme
if u . Scheme != "postgres" && u . Scheme != "postgresql" {
return fmt . Errorf ( "URL scheme must be 'postgres' or 'postgresql', got ' %s '" , u . Scheme )
}
// Check host
if u . Host == "" {
return fmt . Errorf ( "URL must contain a host" )
}
// Check database name
if u . Path == "" || u . Path == "/" {
return fmt . Errorf ( "URL must contain a database name" )
}
return nil
}
Redis configuration
Redis server address in host:port format. REDIS_ADDR = localhost:6379
Redis password. Optional for development, required for production. REDIS_PASSWORD = your-secure-password
Redis database index (0-15). Validated to be within valid range.
Redis database index must be between 0 and 15. Values outside this range will cause startup failure: // internal/config/config.go:72-74
if c . RedisDB < 0 || c . RedisDB > 15 {
logg . Fatal (). Msg ( "REDIS_DB must be between 0 and 15" )
}
Timeout configuration
Maximum time for health check requests to complete.
Maximum time to wait for API server graceful shutdown.
Maximum time to wait for worker tasks to complete during shutdown. WORKER_SHUTDOWN_TIMEOUT = 30s
Set this higher than your longest-running task duration to avoid force-killing tasks.
Logging configuration
Logging destination: stdout, file, or both.
Log file path when using file or both mode. If not specified, defaults to:
API: logs/api.log
Worker: logs/worker.log
Validation
Configuration is validated comprehensively during startup. All validation happens in config.Load():
Required fields
Port validation
Timeout validation
Log output validation
// internal/config/config.go:61-63
if c . DatabaseURL == "" {
logg . Fatal (). Msg ( "DATABASE_URL is required" )
}
Fail-fast philosophy
Boiler-Go validates all configuration at startup and exits immediately if anything is wrong:
✅ Good: Clear failure
❌ Bad: Silent failure
FATA failed to load config error="REDIS_DB must be between 0 and 15"
Application exits immediately with a clear error message. INFO redis connection failed
INFO retrying redis connection...
INFO redis connection failed
Application runs with broken configuration, wasting time debugging.
This fail-fast approach ensures you catch configuration errors during deployment, not in production.
Example configurations
Development
# Server
APP_PORT = 8080
# Database
DATABASE_URL = postgres://user:pass@localhost:5432/boiler_dev
# Redis
REDIS_ADDR = localhost:6379
REDIS_PASSWORD =
REDIS_DB = 0
# Timeouts
HEALTH_CHECK_TIMEOUT = 2s
API_SHUTDOWN_TIMEOUT = 10s
WORKER_SHUTDOWN_TIMEOUT = 30s
# Logging
LOG_OUTPUT = stdout
Production
# Server
APP_PORT = 8080
# Database
DATABASE_URL = postgres://user:secure-pass@db.example.com:5432/boiler_prod
# Redis
REDIS_ADDR = redis.example.com:6379
REDIS_PASSWORD = secure-redis-password
REDIS_DB = 0
# Timeouts
HEALTH_CHECK_TIMEOUT = 5s
API_SHUTDOWN_TIMEOUT = 30s
WORKER_SHUTDOWN_TIMEOUT = 60s
# Logging
LOG_OUTPUT = both
LOG_FILE = /var/log/boiler-go/app.log
Never commit .env files containing production credentials to version control.
Usage in code
Load at startup
// cmd/api/main.go:53
cfg := config . Load ( logger . New ())
Access configuration values
func setupServer ( cfg * config . Config ) {
server := & http . Server {
Addr : ":" + cfg . AppPort ,
ReadTimeout : 10 * time . Second ,
WriteTimeout : 10 * time . Second ,
}
}
Best practices
Load once : Configuration is loaded once at startup using sync.Once
Validate early : All validation happens during Load(), before any services start
Use .env for local dev : Keep .env files for local development, use system environment in production
Document defaults : All default values are visible in struct tags
Type safety : Use appropriate types (time.Duration, int) instead of strings
Use different .env files for different environments: # Development
cp .env.example .env
# Production
source .env.production
./boiler-go