This was my Saturday project. I mostly built this for internal use because I found myself copying/pasting similar code across multiple projects, but figured somebody else may be able to get some utility from it:
These days I mostly am deploying my Go code to cloud providers (Google Cloud, AWS, and Azure) and exposing configuration settings via secret managers (aren’t we all?). Sometimes I want to run these services locally and inject environment variables via key/value pairs. This package wraps reading the key/value pairs and uses reflection to turn environment variables into structs:
package main
import "github.com/DeanPDX/dotconfig"
// Our contrived AppConfig with env struct tags:
type AppConfig struct {
MaxBytesPerRequest int `env:"MAX_BYTES_PER_REQUEST"`
APIVersion float64 `env:"API_VERSION"`
IsDev bool `env:"IS_DEV"`
StripeSecret string `env:"STRIPE_SECRET"`
WelcomeMessage string `env:"WELCOME_MESSAGE"`
}
func Main() {
config, err := dotconfig.FromFileName[AppConfig](".env")
// config is ready to use. Float/bool/int values will be
// correctly parsed. If you are developing locally you can
// put an .env file in your working dir to supply the values.
// In the cloud they should come from a secret manager.
}
My goal here was to keep is as simple as possible. Define your struct with env
tags that map properties to environment variables. Then it “just works” in local dev (either by setting local env variables or including a .env
in the working dir) and in the cloud where environment variables are supplied via secret managers.
Here’s the expected format for .env
files:
MAX_BYTES_PER_REQUEST='1024'
API_VERSION='1.19'
# All of these are valie for booleans:
# 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False
IS_DEV='1'
STRIPE_SECRET='sk_test_insertkeyhere'
# Right now supporting newlines via "\n" in strings:
WELCOME_MESSAGE='Hello,\nWelcome to the app!\n-The App Dev Team'
The decoding logic borrows heavily from encoding/json in the stdlib. I also exposed a function called FromReader in the event that you want to set key/value pairs from something that isn’t a file or you want to manage file IO yourself.
If you have any questions feel free to ask. I’m also open to feedback. Again - I wanted to keep this as simple as possible so the entire package right now is under 200 lines of code. More info and runnable example in the godoc.