Skip to content

Latest commit

 

History

History
34 lines (26 loc) · 1.65 KB

environments.md

File metadata and controls

34 lines (26 loc) · 1.65 KB

Environments

Which fields are required can vary by environment. Declare it with the required tag: * means every environment, a comma-separated list means only those, and no tag means never required. A required field must be set and non-empty in an environment it applies to.

type Config struct {
	DatabaseURL  string `env:"DATABASE_URL" secret:"true" required:"*"`
	SigningKey   string `env:"SIGNING_KEY" secret:"true" required:"production,staging"`
	DevUploadURL string `env:"DEV_UPLOAD_URL" required:"local"`
	Optional     string `env:"OPTIONAL"` // no required tag: never required
}

Required-ness lives only in the required tag. The env library's own required/notEmpty options are not used; Load rejects them, so there is a single, environment-aware source of truth. A required tag on an embedded or nested struct applies to all of its fields, so a group of environment-specific fields can be declared once:

type Config struct {
	Base                          // required:"*" fields, etc.
	DevConfig  `required:"local"` // all of DevConfig's fields are required only in local
}

Tell Load which environment it is loading for with WithEnvironment. A required:"*" field is enforced regardless; a field required in specific environments is enforced only when one is given and matches:

cfg, err := ultra.Load(&config.Config{}, ultra.WithEnvironment("production"))

ultra validate and ultra lint take the environment with --env, so each environment enforces only its own required fields:

ultra validate --secret-resolver aws-secret-manager --env production
ultra lint --secret-resolver externalsecret --env staging