Scheduling Flights and managing runs
A Flight runs on demand, on a schedule, or both. This page covers cron syntax, manual triggers, the run lifecycle, and cancellation.
Cron syntax
Schedules use a standard 5-field cron expression. All times are in UTC.
* * * * *
│ │ │ │ │
│ │ │ │ └── day of week (0-6, Sunday is 0)
│ │ │ └──── month (1-12)
│ │ └────── day of month (1-31)
│ └──────── hour (0-23)
└────────── minute (0-59)
Common cadences:
| Cron | When it fires |
|---|---|
*/15 * * * * | Every 15 minutes |
0 * * * * | Hourly at :00 |
0 6 * * * | Daily at 06:00 UTC |
0 6 * * 1 | Every Monday at 06:00 UTC |
0 0 1 * * | First of the month at 00:00 UTC |
You can set the schedule in the UI under the Schedule panel, through the MCP create_flight or update_flight tools, or through SQL on MD_CREATE_FLIGHT / MD_UPDATE_FLIGHT. Omit schedule_cron to make the Flight on-demand only.
Changing or clearing a schedule
Update the cron expression with MD_UPDATE_FLIGHT when the cadence changes:
CALL MD_UPDATE_FLIGHT(
flight_id := '<flight_id>',
schedule_cron := '0 7 * * *'
);
To stop the schedule from firing, pass schedule_cron := '' (empty string) to update_flight or MD_UPDATE_FLIGHT. The Flight reverts to on-demand only.
CALL MD_UPDATE_FLIGHT(
flight_id := '<flight_id>',
schedule_cron := ''
);
In the UI, clearing the cron expression has the same effect.
Triggering an on-demand run
You can run any Flight manually, with or without a schedule.
- MCP / AI agent
- SQL
Ask your AI agent to trigger the run. The MCP tool is run_flight:
"Run the heartbeat Flight and show me the logs when it finishes."
The agent calls run_flight, then polls list_flight_runs and get_flight_run_logs until the run reaches a terminal state.
CALL MD_RUN_FLIGHT(flight_id := '<flight_id>');
run_flight returns immediately with a new run in RUN_STATUS_PENDING. The run is asynchronous: poll for completion.
Override config for a single run
Pass a config map to MD_RUN_FLIGHT to override stored config values for one run, without editing the Flight or creating a version. You can only set keys the Flight already defines:
CALL MD_RUN_FLIGHT(
flight_id := '<flight_id>',
config := MAP {'LOAD_PARTITION': '2024'}
);
Each run records the config it used, visible in the config column of MD_LIST_FLIGHT_RUNS. See Authentication, config, and secrets for the full pattern.
The run lifecycle
| Status | Meaning |
|---|---|
RUN_STATUS_PENDING | The run is queued and waiting for a runtime to start. |
RUN_STATUS_RUNNING | The runtime is executing main(). |
RUN_STATUS_SUCCEEDED | main() returned without raising. |
RUN_STATUS_FAILED | main() raised or the runtime reported a failure. |
RUN_STATUS_CANCELLED | The run was cancelled before completion. |
Watching for completion
Runs are asynchronous, so triggering one doesn't block. Poll for the latest runs through the MCP list_flight_runs tool, through SQL with MD_LIST_FLIGHT_RUNS, or through the UI's Runs panel. Runs are returned newest first.
SELECT run_number, status, flight_version, created_at
FROM MD_LIST_FLIGHT_RUNS(flight_id := '<flight_id>')
ORDER BY run_number DESC
LIMIT 10;
To read combined stdout and stderr for a single run, use get_flight_run_logs (MCP) or MD_GET_FLIGHT_LOGS (SQL). When the log is large, the response is the tail.
Cancelling a run
You can cancel a run that's still RUN_STATUS_PENDING or RUN_STATUS_RUNNING:
- UI: open the run, then click Cancel run.
- MCP:
cancel_flight_run(flight_id, run_number). - SQL:
CALL MD_CANCEL_FLIGHT_RUN(flight_id := '<flight_id>', run_number := <n>);
Cancelling a run that's already in a terminal status (RUN_STATUS_SUCCEEDED, RUN_STATUS_FAILED, RUN_STATUS_CANCELLED) returns an error.
Time zones
Schedules are always in UTC. The MotherDuck UI shows a local time / UTC toggle on the Runs panel so you can read timestamps in your local zone, but the cron expression itself is interpreted in UTC.
If you need a Flight to fire at 09:00 in a non-UTC zone, do the conversion when you set the schedule. For example, 09:00 in Amsterdam during summer time (CEST, UTC+2) is 0 7 * * * in cron.
Versions and in-flight runs
When a run starts, it locks to the Flight version that was current at that moment. If you update the Flight while a run is in progress, the in-progress run finishes against the version it started with; only the next run picks up the updated source.
This means a long-running Flight is always reproducible against a specific version: you can find that version through list_flight_versions or MD_LIST_FLIGHT_VERSIONS and inspect the exact source code it ran.