A comprehensive Go package for parsing .env files with full grammar support, implementing the same features as mature dotenv loaders in other languages.
go get github.com/nyxstack/dotenvImport in your Go code:
import "github.com/nyxstack/dotenv"- ✅ Full .env grammar support
- ✅ Export syntax:
export KEY=value - ✅ Quoted strings: Double quotes with escapes, single quotes literal
- ✅ Variable expansion:
$VARand${VAR}syntax - ✅ Inline comments:
KEY=value # comment - ✅ Escape sequences:
\n,\t,\",\\, etc. - ✅ Unquoted values with spaces:
KEY=some value - ✅ Empty values:
KEY= - ✅ Comprehensive error handling
| Feature | This Package | godotenv | joho/godotenv |
|---|---|---|---|
| Variable expansion | ✅ | ❌ | ❌ |
| Inline comments | ✅ | ❌ | ❌ |
| Export syntax | ✅ | ❌ | ❌ |
| Proper escape sequences | ✅ | ❌ | ❌ |
| Single quote literals | ✅ | ❌ | ❌ |
| Detailed error messages | ✅ | ❌ | ❌ |
| Full .env compatibility | ✅ | ❌ | ❌ |
package main
import (
"fmt"
"log"
"dotenv"
)
func main() {
// Load from file
env, err := dotenv.Load(".env")
if err != nil {
log.Fatal(err)
}
// Access values
fmt.Println("Database URL:", env["DATABASE_URL"])
// Apply to current process
err = dotenv.Apply(env)
if err != nil {
log.Fatal(err)
}
}package main
import (
"fmt"
"log"
"time"
"dotenv"
)
type Config struct {
DatabaseURL string `env:"DATABASE_URL,required"`
Port int `env:"PORT,default=8080"`
Debug bool `env:"DEBUG,default=false"`
RequestTimeout time.Duration `env:"REQUEST_TIMEOUT,default=30s"`
Features []string `env:"FEATURES"`
}
func main() {
// Load .env file first
dotenv.LoadAndApply(".env")
// Populate struct from environment
var config Config
err := dotenv.Unmarshal(&config)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Server running on port %d\n", config.Port)
fmt.Printf("Debug mode: %t\n", config.Debug)
fmt.Printf("Features: %v\n", config.Features)
}package main
import (
"fmt"
"time"
"dotenv"
)
func main() {
// Load configuration with type safety and defaults
host := dotenv.Env("DATABASE_HOST", "localhost")
port := dotenv.EnvInt("DATABASE_PORT", 5432)
ssl := dotenv.EnvBool("DATABASE_SSL", false)
timeout := dotenv.EnvDuration("DATABASE_TIMEOUT", 30*time.Second)
maxConn := dotenv.EnvInt64("MAX_CONNECTIONS", 100)
fmt.Printf("Connecting to %s:%d (SSL: %t, Timeout: %v, MaxConn: %d)\n",
host, port, ssl, timeout, maxConn)
}The package supports a complete configuration management lifecycle:
// 1. Define configuration struct
type AppConfig struct {
DatabaseURL string `env:"DATABASE_URL,required"`
Port int `env:"PORT,default=8080"`
Debug bool `env:"DEBUG,default=false"`
Features []string `env:"FEATURES"`
}
// 2. Create config with application defaults
config := AppConfig{
DatabaseURL: "postgresql://localhost:5432/app",
Port: 3000,
Debug: true,
Features: []string{"auth", "logging"},
}
// 3. Export config to .env file
err := dotenv.MarshalToFile("app.env", &config)
// 4. Later, load config from environment
dotenv.LoadAndApply("app.env")
var loadedConfig AppConfig
err = dotenv.Unmarshal(&loadedConfig)
// 5. Modify and save back
loadedConfig.Port = 8080
loadedConfig.Features = append(loadedConfig.Features, "metrics")
err = dotenv.MarshalToFile("app.env", &loadedConfig)// Development config
devConfig := Config{DatabaseURL: "localhost:5432/app_dev"}
dotenv.MarshalToFileWithPrefix("dev.env", &devConfig, "DEV_")
// Production config
prodConfig := Config{DatabaseURL: "prod-db:5432/app"}
dotenv.MarshalToFileWithPrefix("prod.env", &prodConfig, "PROD_")
// Load based on environment
env := os.Getenv("ENVIRONMENT")
prefix := strings.ToUpper(env) + "_"
err := dotenv.LoadAndApply(env + ".env")
err = dotenv.UnmarshalWithPrefix(&config, prefix)KEY1=value1
KEY2=value2
KEY3= # empty valueexport NODE_ENV=production
export DEBUG=true# Double quotes allow escapes
MESSAGE="Hello\nWorld\t!"
PATH="C:\\Program Files\\App"
# Single quotes are literal
LITERAL='No escapes\n here'
REGEX='^\d{3}-\d{3}-\d{4}$'HOME_DIR=/home/user
CONFIG_PATH="${HOME_DIR}/config" # ${VAR} syntax
BACKUP_PATH="$HOME_DIR/backups" # $VAR syntax
# Expansion only works in double quotes
NO_EXPAND='$HOME/literal' # stays literalMAX_CONNECTIONS=100 # Database connection limit
API_URL="https://api.example.com" # Production API
# Comments inside quotes are preserved
PASSWORD="secret#123!" # The # is part of the passwordAPP_NAME=My Application Name
LOG_FORMAT=%timestamp% %level%: %message%For comprehensive API documentation, usage examples, and best practices, see:
- Usage Guide - Complete guide to using the package
- API Reference - Detailed API documentation
- Examples - Practical examples and patterns
- AI Agents Guide - Quick reference for AI assistants
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.