A Go package for recursively replacing environment variable references in Go data structures with their actual values from the environment.
- Comprehensive Type Support: Works with structs, slices, maps, arrays, and pointers
- Nested Structures: Handles deeply nested and complex data structures
- Safe Pointer Handling: Safely processes nil pointers without panics
- In-Place Modification: Modifies data structures in-place for efficiency
- Environment Variable Format: Uses
$VAR_NAME
format for variable references - Missing Variable Handling: Replaces undefined or empty variables with empty strings
- Zero Dependencies: Pure Go implementation with no external dependencies
go get github.com/iamolegga/goenvsubst
package main
import (
"fmt"
"os"
"github.com/iamolegga/goenvsubst"
)
func main() {
// Set environment variable
os.Setenv("DATABASE_URL", "postgres://localhost:5432/mydb")
config := &struct {
DatabaseURL string
Debug bool
}{
DatabaseURL: "$DATABASE_URL",
Debug: true,
}
err := goenvsubst.Do(config)
if err != nil {
panic(err)
}
fmt.Printf("Database URL: %s\n", config.DatabaseURL)
// Output: Database URL: postgres://localhost:5432/mydb
}
type Config struct {
Host string
Port string
Username string
Password string
}
config := &Config{
Host: "$DB_HOST",
Port: "$DB_PORT",
Username: "$DB_USER",
Password: "$DB_PASS",
}
goenvsubst.Do(config)
// Slice
urls := &[]string{"$API_URL", "$BACKUP_URL", "https://static.example.com"}
goenvsubst.Do(urls)
// Array
servers := &[3]string{"$SERVER1", "$SERVER2", "$SERVER3"}
goenvsubst.Do(servers)
config := &map[string]string{
"database_url": "$DATABASE_URL",
"redis_url": "$REDIS_URL",
"api_key": "$API_KEY",
}
goenvsubst.Do(config)
// Note: Map keys are never modified, only values
type DatabaseConfig struct {
URL string
Username string
Password string
}
type AppConfig struct {
Database DatabaseConfig
Services []string
Env map[string]string
}
config := &AppConfig{
Database: DatabaseConfig{
URL: "$DATABASE_URL",
Username: "$DB_USER",
Password: "$DB_PASS",
},
Services: []string{"$SERVICE1", "$SERVICE2"},
Env: map[string]string{
"LOG_LEVEL": "$LOG_LEVEL",
"DEBUG": "$DEBUG_MODE",
},
}
goenvsubst.Do(config)
// Safe with nil pointers
var config *struct{ Value string }
goenvsubst.Do(&config) // No error, no operation
// Works with actual pointers
value := "$MY_VALUE"
ptr := &value
goenvsubst.Do(&ptr)
Type | Support | Notes |
---|---|---|
string |
✅ | Environment variables are substituted |
struct |
✅ | All string fields are processed recursively |
slice |
✅ | All elements are processed recursively |
array |
✅ | All elements are processed recursively |
map |
✅ | Only values are processed, keys remain unchanged |
pointer |
✅ | Safely handles nil pointers |
int , bool , etc. |
✅ | Non-string types are ignored (no substitution) |
interface{} |
❌ | Not currently supported |
Environment variables should be referenced using the $VAR_NAME
format:
// Supported formats
"$DATABASE_URL" // ✅ Full string replacement
"$MISSING_VAR" // ✅ Undefined vars become empty strings
// Not supported formats
"${DATABASE_URL}" // ❌ Braces not supported
"prefix-$API_KEY-suffix" // ❌ Partial substitution not supported
The Do
function returns an error for future extensibility, but currently is designed to be robust:
err := goenvsubst.Do(config)
if err != nil {
log.Printf("Failed to substitute environment variables: %v", err)
return
}
- In-Place Modification: The function modifies the input data structure directly
- Map Keys: Only map values are processed, keys are never modified
- Missing Variables: Undefined or empty environment variables are replaced with empty strings
- Thread Safety: Safe for concurrent use (doesn't modify global state)
- Nil Pointers: Handled safely without causing panics
- Type Safety: Only string values are processed for substitution
Run the tests:
go test -v
Run example tests:
go test -v -run Example
For detailed documentation and more examples, visit: pkg.go.dev Documentation
MIT License - see LICENSE file for details.