Home / Data Platform / Airflow

Data PlatformCheat sheetBeginner

Airflow CLI cheat sheet for on-call: check DAGs, pause, trigger, clear tasks and change pools

The Airflow commands on-call engineers use most, for health checks, failed runs, pausing, triggering, clearing tasks, backfills and pools, with the syntax changes between Airflow 2 and 3.

Deepak Bhardwaj7 min read

Applies toApache Airflow 3.x (checked against the 3.3.2 CLI reference), with Airflow 2 differences noted. Run airflow <command> --help to confirm options on your build.

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 -y first and read the task list it prints. Leaving out -s and -e widens the clear to the DAG's whole history. -t load also matches preload_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-05 covers 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 test runs the real task code. If it writes to production tables or calls external APIs, those changes really happen.

Caution

airflow dags delete my_dag deletes 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-errors output and airflow jobs check failures so you hear about them before a data SLA is missed.
  • Make tasks idempotent so tasks clear is 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, trigger and backfill all changed syntax between Airflow 2 and 3.