Airflow schedule_interval (Cron)
Airflow DAGs accept a standard five-field cron string for schedule (schedule_interval in older versions), or a preset such as @daily. A key quirk: Airflow runs a DAG at the END of each interval, so a @daily DAG for a given day runs the next midnight.
Setting the schedule
In the DAG: schedule="0 0 * * *" (or schedule_interval pre-2.4). Presets also work: @daily, @hourly, @weekly. Every 15 minutes: */15 * * * *.
The end-of-interval rule
Airflow triggers a run after the interval completes. A @daily DAG with data_interval of 2026-10-01 actually executes at 2026-10-02 00:00. The logical/execution date is the start of the interval, not the wall-clock run time.
start_date and catchup
Runs begin after start_date. If catchup=True (older default), Airflow backfills every missed interval since start_date — set catchup=False to only run going forward.
FAQ
Does Airflow use standard cron for schedule_interval?
Yes — a 5-field cron string, or presets like @daily, @hourly, @weekly. Newer Airflow uses the 'schedule' parameter.
Why does my Airflow @daily DAG run a day late?
Airflow runs at the end of each interval. The run for 2026-10-01 fires at 2026-10-02 00:00; the execution date marks the interval start, not the run time.
How do I stop Airflow backfilling old runs?
Set catchup=False on the DAG so it only schedules runs going forward from start_date instead of filling every missed interval.