Airflow Configuration: One Typo That Took Down Workers
Airflow config typo in airflow.cfg crashed every worker at restart.
20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.
- ✓You edit airflow.cfg and deploy Airflow services
- ✓You understand env vars, INI files, and secrets managers
- ✓You run CI that can gate config changes
- Airflow config layers defaults, airflow.cfg file, AIRFLOW__SECTION__KEY env vars, and secrets backends, with env overriding file
- Key components: airflow.cfg sections, env-var precedence, airflow config list/lint validation, plugins folder
- Performance insight: a duplicated [core] section reset parallelism from 128 to 32 and cut throughput 75% until validated config restored it
- Production insight: hand-edited configs drift across hosts, so manage config-as-code with CI gates and single-source env files
Think of Airflow config as a restaurant's recipe book with sticky notes. The printed book is airflow.cfg, sticky notes are env vars that override recipes, and a locked safe holds secret sauces. Two identical chapter headings mean cooks follow the wrong one and dinner service collapses.
One duplicated section header took down every worker. The file looked right at a glance and parsed wrong on every restart.
Config feels boring until it's the blast radius. A single typo in airflow.cfg fans out to schedulers, workers, and webservers simultaneously.
Treat config as code with validation gates. You'll learn that discipline here.
The Config Hierarchy Explained
Effective config resolves in seven layers: plain env var first, then _CMD env, then _SECRET env, then airflow.cfg value, then _cmd in file, then _secret in file, and built-in defaults last. Each layer overrides the next, which means a stray env var beats a careful file edit every time. Only nine sensitive keys support _cmd/_secret derivation: database sql_alchemy_conn, core fernet_key, celery broker_url/flower_basic_auth/result_backend, atlas password, smtp smtp_password, api secret_key, and api_auth jwt_secret.
That layering is why debugging starts with airflow config list, not with reading the file. The list command prints what services actually use, including which source won; add --include-sources, --include-env-vars, or --section core to slice it. Get one key fast with airflow config get-value core executor. Files show intent; list shows truth.
Design for it: files carry dev defaults, env carries deployed overrides, backends carry secrets. Never the reverse. For security-sensitive fleets, scope env vars to the components that need them instead of sharing every secret everywhere, and keep clocks in sync with ntpd or log and API auth calls start failing.
Env-Var Precedence in Practice
Env vars follow AIRFLOW__SECTION__KEY with double underscores: AIRFLOW__CORE__PARALLELISM maps to [core] parallelism. Uppercase throughout, dots become underscores, so [providers.some_provider] this_param becomes AIRFLOW__PROVIDERS_SOME_PROVIDER__THIS_PARAM. One typo in the section name creates a silently ignored variable. The same naming extends to _CMD and _SECRET variants for the nine derivable keys.
Prefer env for anything that differs per environment: executors, parallelism, DB URLs, heartbeat intervals. Generate a commented baseline with airflow config list --defaults > "$AIRFLOW_HOME/airflow.cfg", then uncomment only what you change so upgrades inherit new defaults. Keep airflow.cfg minimal so diffs stay readable.
Audit env regularly. Stale exports in systemd units and compose files outlive the engineers who set them and override current intent.
Config-as-Code in CI
Config-as-code means every environment's effective config lives in version control and deploys through CI. Env files per environment, Helm values for clusters, secrets referenced never embedded. Diffs between staging and prod show exactly what differs.
Gate changes: airflow config lint catches renamed keys, airflow config list snapshots catch drift, DAG parse tests catch fallout. A config PR that fails lint never reaches workers.
Canary the rollout: one scheduler first, watch heartbeats and queued age, then the fleet. Config errors announce themselves within minutes when you watch the right signals.
Validating With Config List
airflow config list prints effective values with origins; run it on broken and healthy hosts and diff. airflow config lint flags removed or renamed keys after upgrades. Both belong in CI and in runbooks.
The duplicate-section check is one grep: grep -n '^\[' airflow.cfg should show each header once. Twice means the parser silently picks a winner and your workers run on values you didn't choose.
Snapshot effective config nightly. A cron writing airflow config list to versioned storage turns mystery drift into a dated diff.
Plugins and the Plugin Folder
Some config isn't INI at all. Cluster policies, advanced logging, DAG serialization, pod mutation hooks, parse timeouts, UI customization, extra exported variables, and DB setup live in airflow_local_settings.py. Put that file in $AIRFLOW_HOME/config (on sys.path at init), never in dags/: since 2.10.1 the dags folder left sys.path, so settings parked there silently never import.
Guard every plugin import with try/except and lazy loading. Parse-test plugins in CI with airflow dags list-import-errors. Version the folder alongside DAGs so rollbacks revert both together.
Keep plugins small. Business logic belongs in tasks and packages, not in startup-loaded modules that can halt the fleet.
Version-Specific Config Drift
Upgrades rename and remove keys regularly. Old files carry dead names that new code ignores, so services run on defaults while operators believe their tuning applies. That's how parallelism silently halves overnight.
The defense is mechanical: pin versions, read the changelog's config section, run lint, diff effective config staging versus prod. Ten minutes of checklist saves a night of worker triage.
Track renames in your config repo's history. Future you will thank past you when the next major bumps the same keys.
One Typo That Took Down Workers. A duplicated section reset parallelism silently.
- Config changes need the same review and validation gates as code changes, or one typo costs you 4 workers.
- A single source of truth per environment beats hand-edited files on hosts.
| File | Command / Code | Purpose |
|---|---|---|
| env | export AIRFLOW__CORE__EXECUTOR="CeleryExecutor" | Env-Var Precedence in Practice |
| config | [core] | Validating With Config List |
Key takeaways
Common mistakes to avoid
4 patternsHand-editing airflow.cfg on servers over SSH
Duplicated INI sections after copy-paste merges
Ignoring version-specific config renames across upgrades
Dropping untested plugins into the folder on prod
Interview Questions on This Topic
How can a config typo take down every worker?
Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.
That's Airflow. Mark it forged?
3 min read · try the examples if you haven't