What You’ll Master Here
Your DAG names things it needs; the environment supplies them. The code says conn_id="warehouse" and never knows what that resolves to.
Connections hold credentials. Variables hold configuration. Both are resolved at run time from outside your DAG file, which is what lets the same code run against a laptop database in development and a warehouse in production without a single line changing.
This chapter covers the model, the exact lookup order Airflow uses, and the one performance mistake that appears in almost every Airflow deployment eventually.
Your DAG names things it needs; the environment supplies them. The code says conn_id="warehouse" and never knows what that resolves to.
Getting this right is what makes environment promotion safe and what keeps credentials out of version control. Getting it wrong produces either a secret in a git history — which is a permanent problem — or a scheduler degraded by configuration lookups.
- Connection
- A stored credential and endpoint, retrieved by conn_id. Never appears in your DAG file as a value.
- Variable
- A stored configuration value, retrieved by key. Suitable for settings, never for secrets you can put in a connection instead.
- conn_id
- The identifier your code passes. The only part of a connection that belongs in version control.
export AIRFLOW_CONN_WAREHOUSE='postgres://airflow:***@warehouse.internal:5432/analytics'# AWS Secrets Manager, under the configured prefix
airflow/connections/warehouse -> postgres://airflow:***@warehouse.internal:5432/analyticshook = PostgresHook(conn_id="warehouse")
# the credential is resolved at run time, on the workerPutting a credential directly in a DAG file, even temporarily. It enters git history permanently. Removing the line does not remove the secret, and rotating it becomes mandatory rather than optional.
Reference conn_id and nothing else. If a credential appears in a diff, stop.
Use identical conn_ids across environments so promotion changes no code.
Prefer connections over variables for anything credential-shaped — connections are built for it.
Your DAG names the connection it needs. Resolution happens on the worker, at run time, from whichever source the deployment is configured with.
The DAG names what it needs; the environment supplies it. That separation is what makes one file work everywhere.
