Lesson 5 · Scheduling & execution

Scheduling & data intervals

The one thing everyone gets wrong: when a scheduled run actually fires.

Your win: explain schedule, start_date, and the data interval — and correctly answer "when does a daily DAG for Jan 1 run?" (the question that catches people).

schedule + start_date

A DAG's schedule says how often it runs — a cron string ("0 18 * * *"), a preset, a timedelta, None (manual), or a dataset trigger. Its start_date is the first logical date it's scheduled from. Together they define the sequence of runs.1 (Airflow 3 uses schedule; Airflow 2 called it schedule_interval.)

Each run covers a data interval

Every DAG run is tied to a data interval — the time window of data it should process (data_interval_startdata_interval_end). The logical date is the start of that interval (it used to be called the "execution date" — a misleading name).2

The interview gotcha A scheduled run fires after its data interval ends, not at the start. A daily DAG for the interval 2024-01-01 runs just after 2024-01-02 00:00. Why? Airflow was built for ETL — to summarise Monday's data you must wait until Monday is over. So "the run for Jan 1" happens on Jan 2.
daily schedule: interval [ 2024-01-01 00:00 ───────────── 2024-01-02 00:00 ) logical date = 2024-01-01 (start) ▲ run FIRES here (interval end)
Anchor Our DAGs get their cron from rules.yaml → the template's schedule="{{schedule}}" — e.g. "00 18 * * *" (daily 18:00). The generator defaults an omitted schedule to "0 0 * * *", and schedule: None means manual-trigger only (airflow/dags/rules.yaml · common-spark-job.py). start_date is hard-coded datetime(2024, 1, 1) in the templates.
Read this next

Astronomer — Scheduling in Airflow + DAG Runs

The clearest explanation of data intervals, logical date, and timetables. Pair with the official DAG Runs page.

astronomer.io/docs/learn — Scheduling
airflow.apache.org — DAG Runs

Check yourself (from memory)

Q1. A scheduled DAG run fires…

After the interval ends — the daily Jan-1 run happens on Jan 2. Built for "summarise the period once it's complete."

Q2. The logical date is the…

Start of the interval (formerly "execution date"). It is not when the run executes — that's the confusing part.

Q3. schedule=None means the DAG…

No automatic runs — trigger it by hand or via the API. Several of our rules.yaml entries use schedule: None.
When does a scheduled DAG run actually fire, and what is the logical date?
recall, then click to reveal
A DAG run covers a DATA INTERVAL (data_interval_start..end). The run for an interval fires AFTER the interval ENDS — a daily DAG for 2024-01-01 runs just after 2024-01-02 00:00 (Airflow was built for ETL: summarise a period once it's complete). The LOGICAL DATE is the start of the data interval (formerly "execution date") — NOT when the run executes. schedule (cron/preset/timedelta/None/dataset) + start_date define the intervals; schedule=None = manual only.
Want to see how timetables (Airflow 2.2+) or dataset/asset-driven scheduling generalise this? Ask me.

1. Airflow — Timetables.

2. Astronomer — Scheduling in Airflow.