Configuration
Manage application configuration with environment variables and structured config files in Velocity.
Velocity provides a simple yet powerful configuration system that reads from environment variables and provides structured configuration for framework packages.
Quick Start
import "github.com/velocitykode/velocity/pkg/config"
func main() {
// Get environment variable with fallback
appName := config.Get("APP_NAME", "Velocity")
appEnv := config.Get("APP_ENV", "development")
fmt.Printf("Running %s in %s mode\n", appName, appEnv)
}# .env file
APP_NAME=MyApplication
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com
# Database
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=root
DB_PASSWORD=secret
# Cache
CACHE_DRIVER=redis
REDIS_HOST=localhost
REDIS_PORT=6379import "github.com/velocitykode/velocity/pkg/config"
func main() {
// String with fallback
appName := config.Env("APP_NAME", "Velocity")
// Integer with fallback
port := config.EnvInt("APP_PORT", 4000)
// Boolean with fallback
debug := config.EnvBool("APP_DEBUG", false)
fmt.Printf("%s running on port %d (debug: %v)\n", appName, port, debug)
}Configuration Files
.env File
Create a .env file in your project root:
# Application
APP_NAME=Velocity
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com
APP_PORT=4000
# Crypto (for session encryption)
CRYPTO_KEY=base64:your-32-byte-base64-encoded-key
CRYPTO_CIPHER=AES-256-CBC
# Database
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=velocity
DB_USERNAME=root
DB_PASSWORD=
# Cache
CACHE_DRIVER=redis
CACHE_PREFIX=velocity_cache
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DATABASE=0
# Logging
LOG_DRIVER=file
LOG_PATH=./storage/logs
LOG_LEVEL=debug
# Queue
QUEUE_DRIVER=memory
QUEUE_REDIS_HOST=localhost
QUEUE_REDIS_PORT=6379
# Mail
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@example.com
MAIL_FROM_NAME="${APP_NAME}"
# Session
SESSION_DRIVER=cookie
SESSION_LIFETIME=120
SESSION_SECURE=false
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax
# WebSocket
WEBSOCKET_HOST=0.0.0.0
WEBSOCKET_PORT=6001
WEBSOCKET_PATH=/wsLoading Environment Variables
Environment variables are loaded automatically by the framework, but you can also load them manually:
import (
"github.com/joho/godotenv"
"log"
)
func init() {
// Load .env file
if err := godotenv.Load(); err != nil {
log.Println("No .env file found")
}
}API Reference
Get
Retrieve an environment variable with a fallback:
import "github.com/velocitykode/velocity/pkg/config"
// Get with fallback
appName := config.Get("APP_NAME", "DefaultApp")
// Get without fallback (returns empty string if not set)
apiKey := config.Get("API_KEY", "")Env
Alias for Get - retrieve string environment variable:
// Get string value
appEnv := config.Env("APP_ENV", "development")
appURL := config.Env("APP_URL", "http://localhost:4000")EnvInt
Retrieve an integer environment variable:
// Get integer value
port := config.EnvInt("APP_PORT", 4000)
maxConnections := config.EnvInt("MAX_CONNECTIONS", 100)
// Returns default value if not set or invalid
timeout := config.EnvInt("TIMEOUT", 30)EnvBool
Retrieve a boolean environment variable:
// Get boolean value
debug := config.EnvBool("APP_DEBUG", false)
enableCache := config.EnvBool("ENABLE_CACHE", true)
// Accepts: true, false, 1, 0, yes, no (case-insensitive)Structured Configuration
Logging Configuration
The config package provides structured configuration for logging:
import "github.com/velocitykode/velocity/pkg/config"
// Get logging configuration
loggingConfig := config.GetLoggingConfig()
// Access default channel
defaultChannel := loggingConfig.Default // "stack"
// Get specific channel config
if channelConfig, exists := loggingConfig.GetChannel("daily"); exists {
fmt.Printf("Driver: %s\n", channelConfig.Driver)
fmt.Printf("Path: %s\n", channelConfig.Path)
fmt.Printf("Level: %s\n", channelConfig.Level)
}
// Get default channel config
if defaultConfig, exists := loggingConfig.GetDefaultChannel(); exists {
fmt.Printf("Default driver: %s\n", defaultConfig.Driver)
}Channel Configuration
Configure individual log channels:
type ChannelConfig struct {
Driver string // Driver name (file, console, syslog, null)
Level string // Log level (debug, info, warn, error)
Path string // File path (for file driver)
MaxSize int // Max size in MB
MaxAge int // Max age in days
MaxBackups int // Number of old files to keep
Format string // Format (json, text)
Options map[string]interface{} // Driver-specific options
}Environment-Specific Configuration
Development Environment
APP_ENV=development
APP_DEBUG=true
APP_URL=http://localhost:4000
LOG_LEVEL=debug
LOG_DRIVER=console
CACHE_DRIVER=memory
QUEUE_DRIVER=memory
DB_HOST=localhost
DB_DATABASE=myapp_devProduction Environment
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com
LOG_LEVEL=info
LOG_DRIVER=file
CACHE_DRIVER=redis
QUEUE_DRIVER=redis
DB_HOST=db.example.com
DB_DATABASE=myapp_prodTesting Environment
APP_ENV=testing
APP_DEBUG=true
LOG_LEVEL=error
LOG_DRIVER=null
CACHE_DRIVER=memory
QUEUE_DRIVER=memory
DB_DATABASE=myapp_testConfiguration Patterns
Application Bootstrap
Centralize configuration loading in your app initialization:
package app
import (
"log"
"os"
"github.com/joho/godotenv"
"github.com/velocitykode/velocity/pkg/config"
)
type AppConfig struct {
Name string
Environment string
Debug bool
URL string
Port int
}
func LoadConfig() *AppConfig {
// Load .env file
if err := godotenv.Load(); err != nil {
log.Println("No .env file found, using environment variables")
}
return &AppConfig{
Name: config.Get("APP_NAME", "Velocity"),
Environment: config.Get("APP_ENV", "development"),
Debug: config.EnvBool("APP_DEBUG", false),
URL: config.Get("APP_URL", "http://localhost:4000"),
Port: config.EnvInt("APP_PORT", 4000),
}
}Database Configuration
type DatabaseConfig struct {
Connection string
Host string
Port int
Database string
Username string
Password string
}
func GetDatabaseConfig() *DatabaseConfig {
return &DatabaseConfig{
Connection: config.Get("DB_CONNECTION", "mysql"),
Host: config.Get("DB_HOST", "localhost"),
Port: config.EnvInt("DB_PORT", 3306),
Database: config.Get("DB_DATABASE", "velocity"),
Username: config.Get("DB_USERNAME", "root"),
Password: config.Get("DB_PASSWORD", ""),
}
}Cache Configuration
type CacheConfig struct {
Driver string
Prefix string
Host string
Port int
Password string
Database int
}
func GetCacheConfig() *CacheConfig {
return &CacheConfig{
Driver: config.Get("CACHE_DRIVER", "memory"),
Prefix: config.Get("CACHE_PREFIX", "velocity_cache"),
Host: config.Get("REDIS_HOST", "localhost"),
Port: config.EnvInt("REDIS_PORT", 6379),
Password: config.Get("REDIS_PASSWORD", ""),
Database: config.EnvInt("REDIS_DATABASE", 0),
}
}Mail Configuration
type MailConfig struct {
Driver string
Host string
Port int
Username string
Password string
Encryption string
FromAddress string
FromName string
}
func GetMailConfig() *MailConfig {
return &MailConfig{
Driver: config.Get("MAIL_DRIVER", "smtp"),
Host: config.Get("MAIL_HOST", "localhost"),
Port: config.EnvInt("MAIL_PORT", 1025),
Username: config.Get("MAIL_USERNAME", ""),
Password: config.Get("MAIL_PASSWORD", ""),
Encryption: config.Get("MAIL_ENCRYPTION", "tls"),
FromAddress: config.Get("MAIL_FROM_ADDRESS", "noreply@example.com"),
FromName: config.Get("MAIL_FROM_NAME", config.Get("APP_NAME", "Velocity")),
}
}Security Best Practices
Sensitive Data
Never commit sensitive data to version control:
# .gitignore
.env
.env.local
.env.production
.env.*.localEnvironment Template
Provide a template for required variables:
# .env.example
APP_NAME=Velocity
APP_ENV=development
APP_DEBUG=true
APP_URL=http://localhost:4000
# Database (required)
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
# Crypto (required for production)
CRYPTO_KEY=
# Mail (required for email features)
MAIL_DRIVER=smtp
MAIL_HOST=
MAIL_PORT=
MAIL_USERNAME=
MAIL_PASSWORD=Validation
Validate required configuration on startup:
func validateConfig() error {
required := []string{
"APP_NAME",
"DB_HOST",
"DB_DATABASE",
}
for _, key := range required {
if os.Getenv(key) == "" {
return fmt.Errorf("required environment variable %s is not set", key)
}
}
// Validate crypto key in production
if config.Get("APP_ENV", "") == "production" {
if os.Getenv("CRYPTO_KEY") == "" {
return fmt.Errorf("CRYPTO_KEY is required in production")
}
}
return nil
}Testing Configuration
Test Environment
Create a .env.testing file:
APP_ENV=testing
APP_DEBUG=true
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
CACHE_DRIVER=memory
QUEUE_DRIVER=memory
LOG_DRIVER=nullLoad Test Config
func TestMain(m *testing.M) {
// Load test environment
godotenv.Load(".env.testing")
// Run tests
code := m.Run()
os.Exit(code)
}Docker Integration
Using Environment Variables
# Dockerfile
FROM golang:1.25-alpine
WORKDIR /app
COPY . .
RUN go build -o main .
# Environment variables can be passed at runtime
CMD ["./main"]Docker Compose
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "4000:4000"
environment:
- APP_NAME=MyApp
- APP_ENV=production
- APP_DEBUG=false
- DB_HOST=db
- DB_DATABASE=myapp
- DB_USERNAME=root
- DB_PASSWORD=secret
- REDIS_HOST=redis
depends_on:
- db
- redis
db:
image: mysql:8
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=myapp
redis:
image: redis:alpineBest Practices
- Use Environment Variables: Keep all configuration in environment variables
- Provide Defaults: Always provide sensible defaults for non-sensitive values
- Document Variables: Maintain an
.env.examplefile with all available options - Validate on Startup: Check required configuration before starting the application
- Environment-Specific: Use different
.envfiles for different environments - Security: Never commit
.envfiles to version control - Type Safety: Use
EnvIntandEnvBoolfor non-string values - Centralize: Create configuration structs to centralize access patterns
Examples
Complete Application Setup
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
"github.com/velocitykode/velocity/pkg/config"
)
type Config struct {
App AppConfig
Database DatabaseConfig
Cache CacheConfig
Logging config.LoggingConfig
}
type AppConfig struct {
Name string
Environment string
Debug bool
URL string
Port int
}
type DatabaseConfig struct {
Host string
Port int
Database string
Username string
Password string
}
type CacheConfig struct {
Driver string
Prefix string
}
func LoadAppConfig() (*Config, error) {
// Load .env file
if err := godotenv.Load(); err != nil {
log.Println("No .env file found")
}
// Validate required variables
if err := validateConfig(); err != nil {
return nil, err
}
return &Config{
App: AppConfig{
Name: config.Get("APP_NAME", "Velocity"),
Environment: config.Get("APP_ENV", "development"),
Debug: config.EnvBool("APP_DEBUG", false),
URL: config.Get("APP_URL", "http://localhost:4000"),
Port: config.EnvInt("APP_PORT", 4000),
},
Database: DatabaseConfig{
Host: config.Get("DB_HOST", "localhost"),
Port: config.EnvInt("DB_PORT", 3306),
Database: config.Get("DB_DATABASE", "velocity"),
Username: config.Get("DB_USERNAME", "root"),
Password: config.Get("DB_PASSWORD", ""),
},
Cache: CacheConfig{
Driver: config.Get("CACHE_DRIVER", "memory"),
Prefix: config.Get("CACHE_PREFIX", "velocity_cache"),
},
Logging: config.GetLoggingConfig(),
}, nil
}
func validateConfig() error {
required := []string{"DB_DATABASE"}
for _, key := range required {
if os.Getenv(key) == "" {
return fmt.Errorf("%s is required", key)
}
}
return nil
}
func main() {
cfg, err := LoadAppConfig()
if err != nil {
log.Fatal("Failed to load configuration:", err)
}
fmt.Printf("Starting %s in %s mode on port %d\n",
cfg.App.Name,
cfg.App.Environment,
cfg.App.Port,
)
}
