Skip to content

How-to guides

Each page here solves one problem for someone who already has a store. They assume you have been through a tutorial. If you have not, start there: a how-to shows you the shortest route, not the shape of the thing.

Working with a store

The thirteen jobs that come up whatever your configuration lives in.

Guide Answers
Load and merge How to declare sources, in what order, and what merging does per key.
Read values Getting typed values out, scoping a view, and asking where one came from.
Write configuration Planning and applying a change, where routing sends it, and how to pin it elsewhere.
Validate configuration Schemas and struct-tag validation, at load and before a write lands.
Compose schemas Mounting each component's schema where it lives, bounding what a source may supply, and using config-schema for JSON Schema documents.
Hot-reload Watching sources, observing changes, and what happens when a reload fails.
Typed sections Decoding a subtree into a struct, once or on every change.
Bind CLI flags Making a pflag set a layer, and remapping a flag name to a key.
Compose stores Carrying one store's layers inside another, and promoting a value between them.
Filter a backend Bounding which keys a backend contributes, and accepts writes for.
Test with mocks Faking a backend, a filesystem or a clock without a real service.
Write a custom backend Implementing Backend, and opting into writes and native watch.
Write a format adapter Implementing a codec, and proving it against the conformance suite.

Reading a different file format

The core reads YAML and, because YAML 1.2 is a superset of JSON, a JSON document too. Each of these is a sibling module that teaches it one more format, and your dependency graph carries only the ones you import. Four of the seven add no third-party dependency at all.

Guide Format Writes
JSON JSON and JSON Lines yes
TOML TOML yes
HCL HCL, as a config format yes
XML XML no
dotenv .env files no
INI INI no
Java properties .properties no

A format adapter decides how a file is parsed. Where it lives is the next section's job, and the two compose: you can read TOML out of an S3 bucket.

Reading from a different filesystem

The core ships config.OS() and config.Dir(path). Reach for an adapter when the file lives somewhere neither covers.

Guide Where the file lives Writes
afero an existing afero filesystem yes
io/fs any io/fs.FS, such as embed.FS, zip or tar no
go-billy a go-billy filesystem, as used by go-git yes
SFTP a remote host over SSH yes
AWS S3 an S3 bucket yes
GCP Cloud Storage a GCS bucket yes
Azure Blob an Azure Blob container yes

Reading from a remote system

Configuration that is not a file at all. It is fetched at runtime and takes part in precedence, provenance and hot-reload exactly as a file does.

Guide System Writes Sensitive
Consul HashiCorp Consul KV yes no
etcd etcd v3 yes no
AWS SSM AWS Parameter Store no per-value
Azure App Configuration Azure App Configuration yes no
GCP Parameter Manager GCP Parameter Manager no no
Vault HashiCorp Vault KV v2 no yes
AWS Secrets Manager AWS Secrets Manager no yes
Azure Key Vault Azure Key Vault no yes
GCP Secret Manager GCP Secret Manager no yes
OS keychain macOS / Windows / Secret Service yes yes
filekv a directory of single-value files opt-in opt-in

A sensitive layer is one the core will refuse to write down into a plainer layer beneath it, so a secret cannot be copied into a config file by an ordinary save. The keychain is the one writable secrets backend. Read why it is the exception before you use it.

Getting a client for a remote adapter

Every guide below that talks to a remote system has a Getting a client section listing the ways to obtain one: inject the client you built, hand over the provider's native config, or (for most of them) take the ambient credential chain and supply nothing but the target.

Injection is the default and stays recommended. The reasoning, the cost of each ambient rung, and the adapters that deliberately stop short are in who owns the connection.

Elsewhere

  • The adapter ecosystem: every adapter with its dependency footprint, its status and what it costs.
  • Reference: key syntax, environment-variable rules, struct tags, every error value and every default.
  • Explanation: why the module is built this way.