Flora v1.6.2

Configuration

Flora merges an ordered list of sources into one view, then decodes it. This page covers the source types, how precedence resolves conflicts, and the decoding rules.

Source types

ConstructorReads fromTypical use
File(path)A JSON, TOML, or INI fileBase configuration checked into the repo
Dir(path)Every file in a directory, sortedDrop-in fragments under conf.d/
Env(prefix)Environment variables with a prefixPer-deployment overrides
Flags(set)A parsed flag.FlagSetOne-off command-line overrides
Map(m)An in-memory map[string]anyDefaults and tests

Precedence

Sources passed to Load are applied in order. When two sources define the same key, the later source wins. A common, predictable ordering is:

flora.Load(&cfg,
    flora.Map(defaults),       // lowest priority
    flora.File("config.toml"),
    flora.Env("APP_"),
    flora.Flags(fs),          // highest priority
)
Deterministic merges Merging is a deep, key-by-key overwrite. Maps merge recursively; scalars and slices are replaced wholesale, never appended. The result never depends on map iteration order.

File formats

The format is chosen by file extension: .json, .toml, and .ini. To force a format regardless of extension, pass an explicit decoder:

flora.File("settings.conf", flora.As(flora.TOML))

Custom decoders

Any type implementing the Decoder interface can be registered for an extension:

type Decoder interface {
    Decode(b []byte) (map[string]any, error)
}

flora.Register(".yaml", yamlDecoder{})

Decoding into structs

Field matching uses the flora tag, falling back to a case-insensitive match on the field name. Supported targets:

Unknown keys By default unknown keys are ignored. Pass WithStrict() to make Load return an error when a source contains a key with no matching field — useful for catching typos in production config.

Validation

Validation runs after decoding when WithValidation() is set. Rules are declared in the validate tag and combine with commas.

RuleApplies toMeaning
requiredanyMust be set to a non-zero value
min=N / max=Nnumbers, strings, slicesBounds on value, length, or count
oneof=a b cstringsMust equal one of the listed values
hostportstringsMust parse as host:port

Validation errors are returned as a single ValidationError that lists every failing field, so one run reports all problems at once.

Reading keys directly

When a struct is overkill, load into a *Flora handle and use typed getters:

t, _ := flora.Open(flora.File("config.toml"))
addr := t.String("addr")
size := t.IntOr("cache.size_mb", 64)