What you will be able to do
- Configure the Run on schedule trigger of a deploy job using Intervals, Specific hours or a Cron schedule
- Write cron expressions for dbt jobs, including L and first-weekday-of-month patterns, remembering every time is UTC
- Predict how the scheduler queues, delays or cancels runs of a scheduled job
- Recognise when a state:modified selector makes a scheduled job succeed without building anything
Key concept
Run on schedule — A trigger on a deploy job that tells the dbt scheduler to enqueue a run at recurring times: every N hours, at listed UTC hours, or on a cron expression. Those times only put a run in the queue. When it actually starts depends on the scheduler.
1.Why production runs live on a schedule
Data that nobody rebuilds goes stale. A model materialized as a table holds whatever the last run wrote, so new orders in a source table don't show up until dbt runs again. Scheduling hands that job to the dbt scheduler. It is the engine that queues runs, prepares an environment for them and stores their logs and artifacts, so nobody has to run commands by hand or maintain separate orchestration infrastructure. The quickstarts point out that scheduling a job is sometimes called deploying a project.
Deploy jobs are the job type that runs on a schedule. A deploy job can be triggered by a schedule, by the API or by another job finishing. CI jobs and merge jobs exist for a different purpose: they react to a pull request commit or a merge. A deploy job is created from a deployment environment, so you need one first ([creating a deployment environment](lesson:3.5)). The schedule is set in the job's Triggers section, next to the option to run after another job ([job chaining](lesson:4.8)).
| Job type | Trigger types |
|---|---|
| Deploy jobs | A schedule, API, or the successful completion of another job |
| CI jobs | A commit to a PR or API |
| Merge jobs | A successful merge into the environment's branch or API |
Checkpoint 1 of 9· Check yourself
A team wants a production table rebuilt every morning whether or not anyone merged code. Which job type should carry the recurring schedule?
Deploy jobs build production data assets, and a schedule is one of their triggers. CI and merge jobs react to PR commits and merges.
“Triggered by a schedule, API, or the successful completion of another job.”Source: docs.getdbt.com
2.Choosing between intervals, specific hours and cron
Turning on Run on schedule opens a Timing choice with three modes. Intervals runs the job every set number of hours. Specific hours runs it at a comma-separated list of hours. Cron schedule accepts a full cron expression. With Intervals or Specific hours you also pick Days of the week, which defaults to every day; a cron expression carries its own day-of-month and day-of-week fields instead. A run can also be started by hand with Run now, outside any schedule.
Intervals guarantee even spacing, not exact clock times. Every 2 hours counts from midnight UTC. If the first run lands at 00:04 UTC, the next is at 02:04 and the spacing stays the same after that. Use this mode when a job must run several times a day at a steady rhythm, such as refreshing an operational dashboard.
Specific hours suit jobs tied to the business day. The value 0,12,23 runs the job at midnight, noon and 11 PM UTC. Runs keep the same minute across hours and days, so a job that runs at 00:05 also runs at 12:05 and 23:05 every day. If you need anything these two modes can't express, such as only the first Monday of the month, a particular month, or more often than hourly, use a cron schedule.
| Timing mode | What you enter | When it wins |
|---|---|---|
| Intervals | How often the job runs, in hours (for example Every 2 hours) | Several runs a day at regular spacing |
| Specific hours | Comma-separated UTC hours, such as 0,12,23 | Runs at set times of day, with no need to run more than once a day |
| Cron schedule | Minute, hour, day of month, month and day of week in cron syntax | Complex calendars, such as the first Monday of each month |
Checkpoint 2 of 9· Match them up
Match each requirement to the Timing mode that fits it best
Tap a term, then the definition that fits it.
Intervals handle steady spacing, Specific hours handle a list of times of day, and only cron can express calendar rules like the last day of the month.
“Intervals that run the job every specified number of hours, Specific hours that run the job at specific times of day”Source: docs.getdbt.com
Checkpoint 3 of 9· Exam question
A deploy job has Run on schedule enabled with the Intervals timing method set to every 2 hours, running every day. Due to scheduler processing load, today's first run actually started at 00:04 UTC instead of exactly midnight. At what time will the job's next scheduled run start?
Correct answer: A — 02:04 UTC
- A. Intervals maintain a consistent gap between runs rather than snapping to the top of the hour, so a run that actually started four minutes late pushes every subsequent run forward by that same four minutes. The next 2-hour interval after 00:04 UTC lands at 02:04 UTC.
- B. This assumes the schedule resets to a clean top-of-hour boundary after a delayed run, but Intervals do not re-anchor to 00:00 UTC once a run has drifted. The four-minute offset from the first run carries forward into later runs that day.
- C. This treats the schedule as if it only fires once daily at a fixed clock time, which describes Specific hours behavior, not Intervals. An every-2-hours interval fires repeatedly throughout the same day rather than waiting until the next day.
- D. This snaps the next run to a round number of hours from midnight, ignoring the four-minute delay recorded on the first run. Intervals preserve the actual elapsed time between runs instead of realigning to clean hour marks.
3.Cron expressions, UTC and plan limits
Every dbt schedule runs in UTC. That includes cron. dbt does not convert to your local timezone and does not adjust for daylight saving time. A team in Amsterdam that wants data ready by 07:00 local time has to work out the UTC hour itself. Because UTC doesn't move when the clocks change, the local run time shifts by an hour for part of the year.
A cron expression has five fields: minute, hour, day of the month, month and day of the week. The dbt scheduler also accepts L for the last day of the month, and a day of week written as MON#1 runs on the first Monday of the month. Tools such as crontab.guru turn an expression into plain English, which helps catch a swapped field before it reaches production.
| Expression | Runs |
|---|---|
| 0 * * * * | Every hour, at minute 0 |
| 5 4 * * * | At exactly 4:05 AM UTC |
| 30 */4 * * * | At minute 30 past every 4th hour |
| 0 0 */2 * * | At midnight UTC every other day |
| 0 0 * * 1 | At midnight UTC every Monday |
| 0 0 L * * | At midnight on the last day of the month |
| 0 0 L * FRI,SAT | At midnight on the last day of the month, and on every Friday and Saturday |
| */5 * * * * | Every 5 minutes (not available on Developer plans) |
Combining L with a day of the week adds days rather than narrowing them. 0 0 L * FRI,SAT fires on the last day of the month and also on every Friday and Saturday, not only when the last day happens to be one of those. Likewise 0 7 L * 5 runs at 07:00 on the last day of the month and on Fridays. To restrict the last-day rule to certain months, list them in the month field, as in 0 0 L 7 * for July only.
Checkpoint 4 of 9· Fill the gap
Complete the cron expression so the job runs at 4:00 AM UTC on the first Monday of every month.
0 4 * * ? : At 4:00 AM on the first Monday of every month.The day-of-week field takes MON#1 for the first Monday of the month. MON on its own would run every Monday, and L means the last day of the month.
Source: docs.getdbt.comCheckpoint 5 of 9· Check yourself
What does the expression 0 0 L * FRI,SAT schedule?
The last-day rule and the weekday list are combined as alternatives, so the job runs on the last day of the month and on each Friday and Saturday.
“At 12:00 AM, on the last day of the month, and on Friday and Saturday.”Source: docs.getdbt.com
How often a job may run depends on the plan. On Developer plans the minimum interval is 10 minutes, so an expression like */5 * * * * isn't supported. Starter, Enterprise and Enterprise+ plans have no limit on how often a job runs.
Checkpoint 6 of 9· Exam question
A deploy job uses the Specific hours timing method with the value `0,12,23` and runs every day. Today's midnight run was delayed by scheduler load and actually started at 00:05 UTC. What happens to the run scheduled for hour 12 later that same day?
Correct answer: B — It starts close to 12:00 UTC under its own schedule, since each specific-hours entry targets that fixed clock time independently of the earlier run's delay.
- A. This confuses Specific hours with Intervals, where a delay does carry forward to later runs. Specific-hours entries are independent fixed clock times, so the noon slot is not shifted by whatever happened at the midnight slot.
- B. Each value in the specific-hours list, such as 0, 12, and 23, targets that clock hour on its own each day, subject only to normal scheduler processing time. The noon run is unaffected by the small delay recorded on the midnight run.
- C. The scheduler cancels queued runs only when a job's actual duration exceeds its schedule frequency and causes a backlog, not because an earlier run in the day started a few minutes late. A brief delay on one specific-hours slot does not cause a later slot to be skipped.
- D. This applies interval-style drift accumulation to a specific-hours schedule, which is the wrong mental model. Specific-hours slots do not compound delays from prior runs into later ones on the same day.
Sources4
4.What happens between the scheduled time and the run
A scheduled time enqueues a run. It doesn't start one. When the schedule fires, the run goes into the job queue. Before it can leave the queue, the scheduler checks two things. First, a run slot must be free on the account, because run slots limit how many jobs run at once. Second, the same job must not already have a run in progress. Runs of one deploy job execute one after another so they don't collide while building the same models. Any wait for either reason appears in dbt as wait time.
After both checks pass, the scheduler prepares a short-lived environment, a Kubernetes pod with the right dbt version, environment variables, platform credentials and Git authorization. That prep time varies most at the top of the hour, when the scheduler handles the most run traffic. A schedule at minute 0 starts in the middle of that peak.
Runs that take longer than the schedule interval make a cron-scheduled job over-scheduled. Picture an hourly job whose warehouse data has grown until each run takes 75 minutes. A new run is queued every hour but finishes only every 75 minutes, so the queue grows faster than the scheduler can work through it. For deploy jobs, the scheduler keeps only one run of the job in the queue: when a newer run is queued, the earlier queued run is cancelled with an error message. Over-scheduled jobs triggered by the API are not cancelled this way. You still have to fix the schedule or the job itself. Two other limits matter for jobs left running unattended. A run can last at most 24 hours, and a job is deactivated after 100 consecutive failing runs.
Checkpoint 7 of 9· Check yourself
An hourly cron-scheduled deploy job now takes 75 minutes per run. Which statement describes how the scheduler behaves?
Runs of the same deploy job never overlap. When run time is longer than the schedule interval, the job is over-scheduled and the scheduler cancels surplus runs so the queue doesn't clog.
“Detects over-scheduled jobs and cancels unnecessary runs to avoid queue clog.”Source: docs.getdbt.com
Checkpoint 8 of 9· Exam question
An admin on a Developer plan account tries to save a deploy job's Custom cron schedule set to `*/5 * * * *` so the job runs every 5 minutes. What happens when they attempt to save this schedule?
Correct answer: A — The save is rejected, because Developer plan accounts are limited to a minimum scheduling frequency of every 10 minutes for cron-based job triggers.
- A. Developer plan accounts have a minimum cron frequency floor of every 10 minutes, so a `*/5 * * * *` expression falls below the allowed frequency and cannot be saved. Starter and Enterprise plans do not carry this restriction.
- B. This is backwards: Developer plans are the tier that carries a minimum frequency restriction, while Starter and Enterprise plans have no such cap. Saving an every-5-minutes cron expression on a Developer plan account does not succeed.
- C. The scheduler does not silently rewrite an out-of-range cron expression to a compliant one; it rejects the save outright with a validation error. There is no automatic throttling behavior for over-frequent cron schedules.
- D. Custom cron schedule remains available on Developer plan accounts; the restriction is on how frequent the cron expression can be, not on whether the timing method itself can be selected.
Sources3
5.Scheduled jobs and state:modified selectors
A scheduled job can succeed and still build nothing. This happens when its command uses a state:modified selector. That selector compares the current project with a manifest saved from an earlier run, the deferred manifest, which comes from the last successful deploy job run in the environment or job the comparison points at. It selects only the nodes whose code or configuration differs from that manifest. With or without the trailing +, it detects changes to code, configuration and manifest-relevant metadata, but not changes to the data itself. If nobody has changed the project since that manifest was produced, the nightly run selects zero models and finishes green. New source rows that landed overnight never reach the reporting tables.
The run reports success, so no failure notification goes out. Usually the first sign of trouble is a stakeholder asking why yesterday's numbers are missing. If a job has to rebuild on every scheduled run, remove the state:modified selector from that job. Keep state-based selection for CI and merge jobs, where building only what a pull request or merge changed is the point. Deferral itself is configured with the job's optional settings ([job-level deferral settings](lesson:4.6)).
Checkpoint 9 of 9· Check yourself
A daily scheduled job runs dbt build --select state:modified+ and has shown success with zero models built for a week, while source tables kept receiving new rows. What is the right fix?
state:modified only notices code and configuration changes. New data doesn't count as a change, so a job that must rebuild every run shouldn't use the selector.
“not changes to the data itself, like new rows landing in a source table.”Source: docs.getdbt.com
Sources4
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.A schedule set to hour 6 runs at 6 AM in the user's or account's local timezone and adjusts for daylight saving time.Why is that wrong?
Every dbt schedule, including cron, uses UTC. There is no timezone conversion and no daylight saving adjustment.
Covered in Cron expressions, UTC and plan limits
2.Any plan can schedule a job every 5 minutes with cron.Why is that wrong?
Developer plans have a 10-minute minimum interval. Only Starter, Enterprise and Enterprise+ plans have no limit on job frequency.
Covered in Cron expressions, UTC and plan limits
3.If a scheduled run overruns, the next scheduled run of the same job starts alongside it.Why is that wrong?
Runs of the same job execute one at a time. The queued run waits until the one in progress finishes.
Covered in What happens between the scheduled time and the run
4.A successful scheduled run means the models were rebuilt with the latest data.Why is that wrong?
With a state:modified selector and no code or configuration changes, the job succeeds without building any models.
Covered in Scheduled jobs and state:modified selectors
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.https://docs.getdbt.com/docs/deploy/jobsOfficial docs
“Triggered by a schedule, API, or the successful completion of another job.”
↩︎ Why production runs live on a schedule“Detects over-scheduled jobs and cancels unnecessary runs to avoid queue clog.”
↩︎ Checkpoint - 2.https://docs.getdbt.com/guides/teradataOfficial docs
“Scheduling a job is sometimes referred to as deploying a project.”
↩︎ Why production runs live on a schedule - 3.https://docs.getdbt.com/docs/deploy/job-schedulerOfficial docs
“The scheduler frees teams from having to build and maintain their own infrastructure”
↩︎ Why production runs live on a schedule“Event-driven execution of dbt jobs manually triggered by a user to Run now”
↩︎ Choosing between intervals, specific hours and cron“Is there a run slot that's available on the account for use? — If all run slots are occupied, the queued run will wait.”
↩︎ What happens between the scheduled time and the run“Prep time varies most significantly at the top of the hour when the dbt Scheduler experiences a lot of run traffic.”
↩︎ What happens between the scheduled time and the run“A situation when a cron-scheduled job's run duration becomes longer than the frequency of the job’s schedule”
↩︎ What happens between the scheduled time and the run“If a newer run is queued, the scheduler cancels any previously queued run for that job”
↩︎ What happens between the scheduled time and the run“The scheduler will not cancel over-scheduled jobs triggered by the API.”
↩︎ What happens between the scheduled time and the run“A situation where a job has reached 100 consecutive failing runs or belongs to an inactive account.”
↩︎ What happens between the scheduled time and the run“The scheduler executes distinct runs of the same dbt job serially to avoid model build collisions.”
↩︎ Exam trap 3 - 4.https://docs.getdbt.com/docs/deploy/deploy-jobsOfficial docs
“if the previous scheduled pipeline ran at 00:04 UTC, the next run will be at 02:04 UTC.”
↩︎ Choosing between intervals, specific hours and cron“if you set it to 0,12,23, the job will run at midnight, noon, and 11 PM UTC.”
↩︎ Choosing between intervals, specific hours and cron“so if your job runs at 00:05, 12:05, and 23:05 UTC, it will run at these same hours each day.”
↩︎ Choosing between intervals, specific hours and cron“By default, it’s set to every day when Intervals or Specific hours is chosen for Timing.”
↩︎ Choosing between intervals, specific hours and cron“Cron schedules in dbt use UTC and don't convert to your local timezone or adjust for daylight saving time.”
↩︎ Cron expressions, UTC and plan limits“The dbt job scheduler supports using L to schedule jobs on the last day of the month.”
↩︎ Cron expressions, UTC and plan limits“you can specify the minute, hour, day of the month, month, and day of the week”
↩︎ Cron expressions, UTC and plan limits“0 7 L * 5: At 07:00 AM, on the last day of the month, and on Friday.”
↩︎ Cron expressions, UTC and plan limits“0 0 */2 * *: At 12:00 AM (midnight) UTC every other day.”
↩︎ Cron expressions, UTC and plan limits“remove the state:modified selector from that job. Reserve it for CI or merge jobs”
↩︎ Scheduled jobs and state:modified selectors“state:modified and state:modified+ only detect changes to your project's code, configuration, or manifest-relevant metadata”
↩︎ Scheduled jobs and state:modified selectors“compare against the project representation (which is stored in the manifest.json) of the last successful deploy job run”
↩︎ Scheduled jobs and state:modified selectors“configure it to run on scheduled days and times, enter a custom cron schedule”
↩︎ Key concept“dbt uses Coordinated Universal Time (UTC) for all jobs, including those configured with cron.”
↩︎ Exam trap 1“Starter, Enterprise, and Enterprise+ plans: No restrictions on job execution frequency.”
↩︎ Exam trap 2“When dbt detects no code or configuration changes since the deferred manifest was last produced, the job succeeds without building any models.”
↩︎ Exam trap 4“This doesn't mean that it will run at exactly midnight UTC.”
↩︎ Prediction“Intervals that run the job every specified number of hours, Specific hours that run the job at specific times of day”
↩︎ Checkpoint“At 12:00 AM, on the last day of the month, and on Friday and Saturday.”
↩︎ Checkpoint“not changes to the data itself, like new rows landing in a source table.”
↩︎ Checkpoint