Quick Reference · layered configuration for Python

dynaconf · cheat sheet

One idea underneath everything: config flows through a layered override stack — defaults, then settings files, then .env, then environment variables, then vault/redis. Later layers win. Everything merges into a single settings object you read four equivalent ways, with [environments], @-casting tokens, and validators layered on top.

setup settings files access env & layering casting & dynamic validation & advanced gotcha most common

Introspected from Dynaconf 3.3.3 (installed & run) & cross-checked with: dynaconf.com (official docs) · github.com/dynaconf/dynaconf · PyPI · 12factor.net · DeepWiki · re-verified 2026-08-30: Dynaconf 3.3.5 (5 Aug 2026) current

The override waterfall — where a value comes from, and how you read it back
LOAD ORDER — each layer overrides the one above 1 · defaults (code / Validator default=) 2 · settings.{py,toml,yaml,json,ini} 3 · .secrets.*  ·  vault / redis 4 · .env  (load_dotenv=True) 5 · DYNACONF_* env vars  ⇐ win later wins settings one merged object READ IT — four equivalent ways settings.PORTattr settings['PORT']item settings.get('PORT', 8080)+ default settings.db.hostnested dot first-level keys are case-insensitive ENVIRONMENTS — a horizontal layer, selected by a switcher [default] base values for every env [development] overrides default [production] overrides default Turn on with environments=True. Switch with export ENV_FOR_DYNACONF=production env= at init FORCE_ENV wins stack the sources · merge into one object · switch the environment · read it anywhere — that is the whole library
quickstart · a project in 12 lines
# settings.toml
# [default]
#   name = "myapp"
#   port = 8080
# [production]
#   port = 80

# config.py
from dynaconf import Dynaconf

settings = Dynaconf(
    settings_files=["settings.toml", ".secrets.toml"],
    environments=True,      # enable [default]/[production]
    load_dotenv=True,       # read a .env file too
    envvar_prefix="MYAPP",   # MYAPP_PORT=80 overrides
)

settings.PORT          # 8080  (or 80 if ENV_FOR_DYNACONF=production)
settings.get("NAME")    # "myapp"
01Setup & instantiateDynaconf(...)
02Read your settingsfour equivalent ways
03Settings filestoml · yaml · json · ini · py
04Environment variablesthe override layer
05.env filespython-dotenv
06Layered environmentsdefault · dev · prod
07Type casting tokens@int @bool @json …
08Lazy & interpolation@format · @jinja
09Merging vs overridingextend, don't replace
10Secrets.secrets · vault · redis
11ValidationValidator(...)
12Validator conditionsthe constraint kwargs
13Settings object methodsmanipulate & export
14Command linedynaconf …
15Flaskcontrib · FlaskDynaconf
16Djangocontrib · DjangoDynaconf
17Inspect & debugwhere did this come from?

Four ideas that make the rest obvious

Everything above is one of these four patterns in disguise. Learn the shapes, not the option list.

the override waterfall

A key set in a later source wins. Here PORT starts at a default and is overridden twice on the way down.

defaultPORT=8080 settings.tomlPORT=8080 .env— unset — DYNACONF_PORT80 loads last PORT → 80

environments merge on [default]

Each environment sees [default] plus its own overrides. The switcher picks which column is active.

[default] name=app port=8080 debug=off [development] debug=on [production] port=80 active env = default + its overrides ENV_FOR_DYNACONF selects the column

one value, four ways to read it

Attribute, item, get, and nested dot all resolve against the same merged store. First-level keys are case-insensitive.

settings merged store settings.PORT settings['PORT'] .get('PORT', 80) settings.db.host

a casting token, decoded

A string value can carry a @token that transforms it at load time — cast the type, or interpolate other settings.

@format {this.base_dir}/app.log token @format {this.base_dir} → another setting {env[VAR]} → os env var '/app/app.log'

Worth memorizing

later winsenvvars override files; among files, later-loaded overrides earlier
UPPERCASE + prefixonly DYNACONF_KEY (or your prefix) is read; lowercase is ignored
nested = __double underscore: DYNACONF_DB__host; single won't nest
dicts/lists in envvarsneed TOML {k=v}/[x] or a @json token
environments=Trueoff by default in Dynaconf(); on for Flask/Django
case-insensitivefirst-level keys only; nested reached via .dot
merge, don't clobberdynaconf_merge=true or @merge — else dicts/lists are replaced
gitignore secrets.secrets.*, .env, *.local.* stay out of the repo
FORCE_ENV winsbeats ENV_FOR_DYNACONF — use it in pytest
validate() vs validate_all()latter reports every error, not just the first
True/False → TOML boolauto-lowercased; wrap in @str to keep the string
dynaconf inspectshows exactly which source set a key when debugging