ADR-0022: Group backend settings into nested platform models
- Status: Accepted
- Date: 2026-03-25
- Deciders: avm
- Supersedes:
- Superseded by:
Related ADRs
Context
Flat settings fields work for a tiny scaffold, but they do not scale well once the template owns API runtime, data stores, workers, observability and deployment-facing behavior at the same time. Over time a flat Settings model degrades into:
- dozens of top-level fields without clear ownership;
- duplicated prefixes like
app_*,api_*,observability_*scattered through code; - poor discoverability for new platform modules;
- environment examples that do not communicate grouping or intent;
- higher chance of mixing unrelated concerns in bootstrap code.
The maximum template needs a stricter configuration shape that mirrors platform ownership boundaries directly.
Decision
Backend settings are grouped into nested platform models under a single Settings(BaseSettings) root.
Canonical groups:
settings.appfor service identity and environment metadata;settings.apifor HTTP runtime configuration;settings.dbfor PostgreSQL and Redis connection settings;settings.brokerfor Taskiq/stream worker runtime naming;settings.observabilityfor logging, tracing, metrics and GlitchTip controls.
Rules:
- backend code reads configuration through grouped settings paths such as
settings.api.prefixorsettings.observability.metrics_path; .envand.env.exampleuse nested environment keys with__separators under the existing repository env prefix;- computed fallbacks such as observability service identity may derive from
settings.app, but the owning configuration still lives in grouped models; - new platform-level configuration must be added to an existing group or to a new explicit nested model, not as another flat top-level field.
Consequences
Positive
- settings ownership becomes obvious from the path itself;
- app/bootstrap/runtime code reads cleaner and drifts less;
.env.exampledocuments the platform model instead of just listing unrelated flat variables;- future extensions like workers, auth or integrations have a clear place in the configuration tree.
Negative
- existing local environment files must migrate from flat variables to nested keys;
- code changes that touch settings now require coordinated updates across references, examples and tests.
Neutral
- the root
Settingsobject remains the single entrypoint, but its internal shape becomes intentionally hierarchical.
Alternatives considered
- keep a flat
Settingsmodel and accept growth in top-level fields; - split configuration into multiple independent
BaseSettingsroots without a single composition object; - hardcode runtime-specific configuration near each subsystem instead of modeling ownership in settings.
Follow-up work
- [ ] add new grouped settings models only when a new platform area appears, not pre-emptively
- [ ] keep
.env.examplealigned with grouped settings names on every config change - [ ] add integration docs for deployment systems that need nested env variable templates