Goal
You're on call and need to see what Airflow is doing, or stop or rerun something, without clicking through the UI. Start with health, then the failed run, then act.
Where to run the commands
Run them where Airflow is installed and configured, with access to the metadata database and your DAG files:
# Kubernetes
kubectl exec -n airflow deploy/airflow-scheduler -- airflow dags list-import-errors
# Docker Compose
docker compose exec airflow-scheduler airflow dags list-import-errors
Deployment and service names vary by install. Managed services often restrict the CLI or expose only part of it, so check your provider's documentation.
Print the built-in command list and confirm the version:
airflow version
airflow cheat-sheet
Health checks
| Question | Command |
|---|---|
| Can Airflow reach the metadata DB? | airflow db check |
| Is a scheduler alive? | airflow jobs check --job-type SchedulerJob --allow-multiple --limit 5 |
| Is a triggerer alive? | airflow jobs check --job-type TriggererJob --allow-multiple --limit 5 |
| Which DAGs fail to import? | airflow dags list-import-errors |
| Which DAG files parse slowly? | airflow dags report |
| What value is a setting using? | airflow config get-value core parallelism |
| What are the paths, executor and versions? | airflow info --anonymize |
jobs check exits non-zero when it finds no live job, so you can use it in a liveness probe.
Airflow 2 and 3 differences
| Task | Airflow 2 | Airflow 3 |
|---|---|---|
| List runs of a DAG | airflow dags list-runs -d my_dag | airflow dags list-runs my_dag |
| Trigger with a date | airflow dags trigger my_dag -e 2026-11-05 | airflow dags trigger my_dag -l 2026-11-05T00:00:00+00:00 |
| Backfill | airflow dags backfill my_dag -s 2026-11-01 -e 2026-11-03 | airflow backfill create --dag-id my_dag --from-date 2026-11-01 --to-date 2026-11-03 |
If a command returns unrecognized arguments or invalid choice, check this table and then --help.
Find out what failed
The examples below use Airflow 3 syntax.
# Recent failed runs of one DAG
airflow dags list-runs my_dag --state failed -s 2026-11-05 -o table
# State of one run
airflow dags state my_dag "scheduled__2026-11-05T02:00:00+00:00"
# State of every task in that run
airflow tasks states-for-dag-run my_dag "scheduled__2026-11-05T02:00:00+00:00" -o table
# Just the failed task IDs
airflow tasks states-for-dag-run my_dag "scheduled__2026-11-05T02:00:00+00:00" -o json \
| jq -r '.[] | select(.state == "failed") | .task_id'
Find out why something isn't running
| Symptom | Command | What it tells you |
|---|---|---|
| Task waits with no error | airflow tasks failed-deps my_dag my_task <run_id> | The dependencies that aren't met |
| DAG never starts | airflow dags details my_dag -o yaml | Whether it's paused, plus schedule and bundle details |
| Not sure when it runs next | airflow dags next-execution my_dag -n 3 | The next scheduled logical dates |
| DAG missing from the list | airflow dags list-import-errors | The parse error for that file |
| DAG fixed but UI is stale | airflow dags reserialize | Re-parses DAG files and updates the serialized copies |
Output columns vary by version, so check your build's output before scripting against them.
Pause and unpause
airflow dags pause my_dag
airflow dags unpause my_dag
# Pause every DAG that matches a pattern (check --help that your version has this flag)
airflow dags pause "^finance_" --treat-dag-id-as-regex
Run the regex form without -y first so you can read the list of matched DAGs before you confirm.
Warning
Pausing stops new scheduled runs and stops further tasks from being scheduled, but tasks already running carry on. A manually triggered run on a paused DAG stays queued until you unpause it.
Trigger a run
airflow dags trigger my_dag
airflow dags trigger my_dag -r "manual__rerun_20261105" -c '{"run_date": "2026-11-05"}'
Give incident reruns a clear run ID so they're easy to find later. If you pass -l, Airflow rejects a logical date already used by another run of that DAG.
Clear tasks so they rerun
Clearing resets task instances so the scheduler runs them again. It doesn't undo anything those tasks already wrote.
# Failed tasks only, in a date window
airflow tasks clear my_dag --only-failed \
-s 2026-11-05T00:00:00 -e 2026-11-05T23:59:59
# One task and everything downstream of it
airflow tasks clear my_dag -t "^load_orders$" --downstream \
-s 2026-11-05T00:00:00 -e 2026-11-05T23:59:59
| Flag | Meaning |
|---|---|
-t, --task-regex | Tasks to clear, as a regex |
-s, -e | Start and end of the logical date window |
-d, --downstream | Include downstream tasks |
-u, --upstream | Include upstream tasks |
-f, --only-failed | Only failed tasks |
-r, --only-running | Only running tasks |
-y, --yes | Skip the confirmation prompt |
-R, --dag-regex | Treat the DAG ID as a regex |
Caution
Run it without
-yfirst and read the task list it prints. Leaving out-sand-ewidens the clear to the DAG's whole history.-t loadalso matchespreload_orders, so anchor the pattern with^and$. A task that isn't idempotent, such as a plain append, will write duplicates when it reruns.
Some details to watch:
- A date with no time means midnight, so
-s 2026-11-05 -e 2026-11-05covers a one-instant window. Give the full day as above. - Times without an offset use your configured default time zone, which is UTC unless someone changed it.
- Airflow 3 runs triggered through the API can have no logical date. A date filter won't match those runs, so clear them in the UI.
Backfill (Airflow 3)
Do a dry run first, then cap concurrency so you don't starve current runs:
airflow backfill create --dag-id my_dag \
--from-date 2026-11-01 --to-date 2026-11-03 \
--reprocess-behavior failed --max-active-runs 2 --dry-run
Remove --dry-run when the list of runs looks right.
--reprocess-behavior | Runs it creates |
|---|---|
none | Missing runs only |
failed | Missing and failed runs |
completed | Missing, failed and successful runs |
Pools
airflow pools list -o table
airflow pools get default_pool
# Raise a pool during a backlog (set updates it if it exists)
airflow pools set etl_pool 16 "ETL tasks, raised for INC12345"
# Save and restore definitions
airflow pools export pools.json
airflow pools import pools.json
Before you raise a pool, check that the source system and workers can take the extra load. Put it back when the backlog clears.
Test one task
airflow tasks test my_dag my_task 2026-11-05
This runs the task without checking dependencies or recording state in the metadata database.
Warning
tasks testruns the real task code. If it writes to production tables or calls external APIs, those changes really happen.
Caution
airflow dags delete my_dagdeletes the DAG's metadata, including run history. If the file still exists, the DAG comes back with no history.
Prevent it next time
- Alert on
airflow dags list-import-errorsoutput andairflow jobs checkfailures so you hear about them before a data SLA is missed. - Make tasks idempotent so
tasks clearis safe to use during an incident. - Keep pool definitions in Git with
pools export, and reapply them after a rebuild. - Recheck any scripts that call the CLI when you upgrade.
list-runs,triggerand backfill all changed syntax between Airflow 2 and 3.