Struct tags and types
Parse walks the fields of the struct you hand it and fills each one that has an env tag. This page covers the tags it reads, the field types it accepts and how each type is parsed. Which value wins when several are present is on Defaults and precedence.
Tags
| Tag | Meaning |
|---|---|
env:"NAME" | Fill this field from the environment variable NAME. |
env:"NAME,required" | Same, and fail with ErrRequiredFieldNotSet when no value comes from anywhere. |
default:"value" | Fallback used when NAME is not set. Parsed exactly like an environment value. |
type Config struct {
Port int `env:"PORT" default:"8080"`
APIKey string `env:"API_KEY,required"`
Verbose bool `env:"VERBOSE"`
Ignored string
}
The rules, straight from gonfiguration.go:
- A field without an
envtag is skipped, whatever its type.Ignoredabove is never touched. - The name and options are split on commas and trimmed, so
env:"PORT, required"works. Any option other thanrequiredis ignored without an error. requiredis satisfied by an environment variable that is set, even to an empty string, by adefaulttag, or by a programmatic default.- A tagged field must be exported. An unexported field with an
envtag makesParsepanic (reflect: reflect.Value.SetString using value obtained using unexported field) as soon as a value is applied to it. - Only top-level fields are read. A nested struct, a pointer, a map or any other unsupported type with an
envtag fails the wholeParsewithErrUnsupportedFieldType.
Supported types
| Field type | Parsed with | Accepts |
|---|---|---|
string | nothing | The value as it is, including an empty string. |
bool | strconv.ParseBool | 1, t, T, true, TRUE, True, 0, f, F, false, FALSE, False. |
int, int8, int16, int32, int64 | strconv.ParseInt(value, 10, 64) | Base 10 integers such as -42. No 0x prefix. |
uint, uint8, uint16, uint32, uint64 | strconv.ParseUint(value, 10, 64) | Base 10 integers without a sign, such as 42. |
float32, float64 | strconv.ParseFloat with the field’s bit size | 3.14, 1e-3, and the other forms ParseFloat takes. |
time.Duration | time.ParseDuration | 300ms, 30s, 5m, 1h30m. A bare number such as 30 is rejected. |
[]string | split on ,, each item trimmed | a, b ,c becomes ["a", "b", "c"]. |
A named type over one of the scalar kinds, such as type Mode string or type Port uint16, is accepted and parsed by its kind. time.Duration is matched by type before its int64 kind is looked at, so it gets time.ParseDuration. Slices are matched by exact type, so only []string works; a named slice type such as type Hosts []string fails with ErrUnsupportedFieldType.
Parsing details worth knowing
- Narrow integers wrap without an error. Every integer is parsed as 64 bits and then stored in the field. A value that does not fit the field’s width is truncated:
300in anint8becomes44, and256in auint8becomes0. Only values outside the 64-bit range fail. Validate the range yourself when it matters. - An empty value is not “unset”.
PORT=setsPORTto an empty string. That overrides every default, so anintfield fails becausestrconv.ParseIntrejects"". Astringfield becomes empty, and a[]stringfield becomes an empty slice,[]string{}. []stringhas no escaping. A comma always splits, and empty items stay:a,,bbecomes["a", "", "b"].- Errors quote the value. The
strconvandtime.ParseDurationerrors include the text that failed to parse, so a typo in a secret ends up in the error message. See Errors.