Configuration
maxicfg looks for a file named .maxicfg.yaml in the current
directory and walks up the tree until it finds one. Everything in it is
optional — the tool works with command-line flags alone.
Project file
# .maxicfg.yaml
version: 1
schema: ./config/schema.yaml
profiles:
local:
sources: [config/base.yaml, config/local.yaml]
staging:
sources: [config/base.yaml, config/staging.yaml]
production:
sources: [config/base.yaml, config/production.yaml]
lint:
strict: true # unknown keys become errors
max_depth: 8
scan:
ignore:
- "config/fixtures/**"
- "**/*.example.yaml"
Sources within a profile are merged left to right: later files override earlier ones. This is the usual "base plus overlay" arrangement, and it means the schema only has to describe the merged result.
Schema syntax
A schema is a YAML file with a single top-level keys mapping.
Keys are written in dotted form regardless of the nesting in the source file.
keys:
# a required string
service.name:
type: string
required: true
pattern: "^[a-z][a-z0-9-]{2,40}$"
# an integer with bounds and a default
server.port:
type: int
default: 8080
min: 1
max: 65535
# one of a fixed set of values
logging.level:
type: enum
values: [debug, info, warn, error]
default: info
# a duration, parsed with Go syntax
cache.ttl:
type: duration
default: 5m
# wildcards match any key at that position
features.*:
type: bool
default: false
# nested wildcards work too
databases.*.host:
type: string
required: true
Supported types
| Type | Accepts | Extra options |
|---|---|---|
string | any scalar | pattern, min_len, max_len |
int | integers | min, max |
float | numbers | min, max |
bool | true, false, yes, no, 1, 0 | — |
enum | values from a list | values (required) |
duration | 30s, 5m, 2h30m | min, max |
bytes | 512kb, 4mb, 1gb | min, max |
url | absolute URLs | schemes |
list | sequences | of, min_items, max_items |
Templating
maxicfg render substitutes variables into a template file. The
syntax is intentionally minimal: only variable substitution and defaults, no
loops or conditionals.
# config/production.yaml.tmpl
database:
host: ${DB_HOST}
port: ${DB_PORT:-5432}
pool_size: ${DB_POOL:-40}
logging:
level: ${LOG_LEVEL:-info}
$ DB_HOST=db.internal maxicfg render config/production.yaml.tmpl \
--out config/production.yaml
A variable with no value and no default is an error, not an empty string. This is deliberate — silently rendering an empty host is worse than failing the build.
Ignoring keys
Some keys are expected to differ between environments and should not appear in a diff. Mark them in the schema rather than filtering after the fact:
keys:
database.password:
type: string
required: true
secret: true # never printed, excluded from diff output
deploy.replicas:
type: int
environment_specific: true # excluded from drift reports
Environment variables
| Variable | Effect |
|---|---|
MAXICFG_CONFIG | path to the project file, overrides discovery |
MAXICFG_PROFILE | default profile when --profile is omitted |
MAXICFG_NO_COLOR | disable coloured output |
MAXICFG_LOG | debug enables verbose internal logging |