Triggering a Run by Hand
Concepts covered: Schedules and timetables
Pressing Trigger
Every run so far was created by the scheduler at the moment a window closed. A person can create one too, at any moment, by pressing the trigger button on the DAG's page in the UI or from a terminal. The result is a run like any other: it has a run_id, a logical date, a data interval and 1 task instance per task, and it moves through the same states in the grid. Its run_id begins with manual__ where a scheduled run's begins with scheduled__, and the grid marks it with its own symbol so the 2 kinds are told apart at a glance.
From a terminal, the same run comes from airflow dags trigger daily_sales. The command returns as soon as the run is created, and the run appears in the grid within a few seconds.
The window a manual run is handed
The trigger dialog asks for a logical date and fills in the moment you opened it. Keep that value and the run's logical date is the trigger moment, 14:20 on 5 November, and its run_id is manual__2026-11-05T14:20:00+00:00. Its data interval follows a rule of its own: the most recent window that had already closed at that moment. For daily_sales with its midnight cron, that is 4 November 00:00 to 5 November 00:00, the same window the scheduled run created at midnight was handed.
| Run | Created at | logical_date | Window |
|---|---|---|---|
| `scheduled__2026-11-04T00:00:00+00:00` | 5 Nov 00:00 | 4 Nov 00:00 | 4 Nov 00:00 to 5 Nov 00:00 |
| `manual__2026-11-05T14:20:00+00:00` | 5 Nov 14:20 | 5 Nov 14:20 | 4 Nov 00:00 to 5 Nov 00:00 |
| `scheduled__2026-11-05T00:00:00+00:00` | 6 Nov 00:00 | 5 Nov 00:00 | 5 Nov 00:00 to 6 Nov 00:00 |
In the table, the manual run's logical date and the start of its window differ, where in a scheduled run they coincide: the name says when a person pressed the button, and the window says what data the run reads. The scheduled run at midnight on 6 November is untouched as well. It owns the window that closed at that moment, exactly as if nobody had pressed anything in between.
The schedule does not count manual runs
A manual run changes nothing about the rhythm. The scheduler works out the next scheduled run from the last scheduled one, so triggering at 14:20 neither delays midnight's run nor replaces it, and triggering 3 times in an afternoon leaves 3 extra runs in the grid and the same midnight run on its way. If the DAG is paused when you trigger it, the run is created and sits waiting; its tasks start only once the DAG is unpaused.
- Scheduled run
- Created by the scheduler when a window closes.
- run_id is scheduled__ plus the logical date.
- Logical date equals the window's start.
- Counted by the scheduler when it works out the next run.
- Manual run
- Created when a person presses Trigger or runs the CLI command.
- run_id is manual__ plus the logical date.
- Logical date is the trigger moment; the window is the latest closed one.
- Ignored by the scheduler when it works out the next run.
2 uses for a manual trigger
Trigger by hand on the day a DAG is deployed. Section 2 showed a first run that arrives 15 hours after deployment; a manual trigger at 09:00 produces a run at once, so every task goes green or red long before the first scheduled run. Its window is the latest closed one, 3 November, which lies before start_date, so no scheduled run will ever own it. Read the run as a check that the tasks work, and expect the scheduled run at midnight to write 4 November, the DAG's first window.
A manual trigger also repeats a window that went wrong, where a source was late or a task failed. Type the logical date you want into the dialog and the window follows the same rule, the most recent window closed before that date, so a logical date of noon on 2 November hands the run 1 November to 2 November. Later lessons cover re-running an existing run in place and refilling many windows at once; a single manual run with a chosen date is the first tool for a single bad day.
A DAG with no schedule
A DAG with schedule=None has only manual runs. Since it has no windows to pick from, each run is handed a window of zero length, both ends at the trigger moment, so data_interval_start and data_interval_end are equal and logical_date matches them. Such a DAG suits a job someone runs on demand, a one-off load or a cleanup, where the moment of the run is the only time worth recording.
import pendulum
from airflow.sdk import dag, task
@dag(
dag_id="reload_products",
start_date=pendulum.datetime(2026, 11, 1, tz="UTC"),
schedule=None,
)
def reload_products():
@task
def reload():
...
reload()
reload_products()
- Its run_id starts with manual__ and carries the trigger moment.
- Its window is the latest closed one before its logical date, so read both values.
- The next scheduled run is still due at the next boundary.
- A run triggered on a paused DAG waits until the DAG is unpaused.
About this lesson
This section is part of the Scheduling: Beginner lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.