Job Scheduling
Automate your dbt runs on any schedule. Define when models run, set dependencies between jobs, and monitor execution without leaving dbdeux.
Create Job Wizard
Jobs live in the left navigation under Scheduled Jobs. New jobs are built through a guided wizard that walks you from trigger to a safe preview, so you never hand-edit a job payload or guess what it will do.
Choose How the Job Triggers
Pick the trigger that fits the job instead of forcing everything onto a cron schedule:
- Scheduled: runs on a cron cadence you define
- Manual only: never fires on its own; you run it on demand with Run now. Ideal for backfills and one-off refreshes
- On merge: runs after code merges to a branch you watch
- Both: runs on its schedule and after a merge
Manual-only and on-merge jobs are never scheduled, so they will not surprise you with an unexpected cron run.
Dry-Run Preview
Before you save, run a dry-run preview. dbdeux resolves the full job on the server without persisting anything and shows you exactly what would happen: the commands, the resolved selection, how many models would build, and how many would defer. You catch a mistake before it ever touches your warehouse, not after.
Cycle-Safe Dependencies
When you chain a job to run after another, the wizard validates the dependency graph so you cannot point a job at itself or create a loop. Invalid chains are blocked at creation time.
Pick the Environment
The wizard makes it clear what the job will actually connect to. A new job pre-selects your Production environment by default, and each option spells out what it means:
- With an environment: the job runs with that environment's warehouse connection, variables, and dbt target. This is what you want almost every time
- No environment (repo
profiles.ymlonly): the job has no warehouse connection or variables, so the run only works if your repository commits a self-containedprofiles.yml. The wizard warns you to pick an environment unless you specifically need this
This removes the common surprise of a job that saves fine but fails at run time because it had no connection.
The environment also decides how much work the job does. If the environment has state-aware runs enabled, the job skips models it can prove have not changed since its last successful run, and reports what it skipped and why.
Schedule Builder
Create schedules visually without writing cron expressions:
Preset Schedules
| Schedule | Runs at |
|---|---|
| Hourly | Every hour at :00 |
| Daily | Every day at a time you choose |
| Weekdays | Monday through Friday at a time you choose |
| Weekly | Once per week on a day and time you choose |
| Custom | Any cron expression for complex schedules |
Custom Cron
For advanced use cases, enter any cron expression:
0 6 * * *- Every day at 6:00 AM0 */2 * * *- Every 2 hours0 8 * * 1-5- Weekdays at 8:00 AM0 6,18 * * *- Twice daily at 6:00 AM and 6:00 PM
Job Configuration
Each scheduled job specifies:
- Which models to run: Use dbt selectors (
tag:daily,staging.*,+dim_customers) - Run mode: Run, test, build, or a custom sequence
- dbt version: Pin a specific engine version (Core 1.8, 1.10, or Fusion) per schedule
- Environment: Which environment and connection to use (dbt variables from the environment are injected automatically)
- Timeout: Maximum allowed duration before the job is killed
- Retry policy: Automatically retry on failure (configurable attempts and backoff)
- Concurrency policy: Control whether overlapping runs queue, skip, or cancel the previous run
- Auto-deactivate: Automatically disable the job after N consecutive failures
Scheduled jobs build the dbt connection profile from the environment you select, so a run works even when the environment uses a custom target name that is not defined in your repository's profiles.yml. There is no need to keep a matching target in the repo just to make schedules run.
Per-Job Environment Variable Overrides
Beyond the variables inherited from the environment, each job can define its own variable overrides. This lets one job reuse an environment while changing a handful of values (for example a lookback window or a batch date) without cloning the whole environment.
Defer to Production
Turn on Defer to production so a job builds only what it needs while resolving everything else against your last production build (--defer --state). Selectors like state:modified or a narrow +model run fast without failing on missing upstream relations. If a usable production state is not available, the run proceeds without defer and notes that in the log rather than failing.
Two controls give you fine-grained command over how defer behaves:
- Favor deferred state: prefer the deferred (production) relation even when a stale copy exists in the job's own target schema (
--favor-state), so you always compare against trusted data - Selectable defer source: choose which environment's build to defer against, rather than always assuming production
A readiness panel tells you up front whether deferred state is available for the environment you picked, so you know the option will actually take effect before you save the job.
Source Freshness Pre-Check
Enable Check source freshness first to run dbt source freshness before the rest of the job. If upstream data is stale, you find out before spending compute rebuilding models on old inputs.
A freshness check is only as good as its cadence, so the wizard shows an SLA-aware cadence hint: it compares the job's schedule against your project's tightest source freshness threshold and warns you when the job runs less often than a source's SLA expects. That keeps a daily job from quietly reporting an hourly source as "fresh."
Keep Documentation Current
Tick Generate docs on run and the job refreshes your Atlas Catalog documentation after its steps succeed. Instead of documentation being something a person remembers to regenerate, your catalog stays as current as your last successful production build, and each generation publishes a new catalog version you can browse and compare.
It is deliberately safe to leave on: documentation is generated only after the job's real work has succeeded, and if the documentation step itself has a problem, your run is still reported as the success it was. Nobody gets paged because a docs refresh hiccuped.
Ordered Steps
A single job can run more than one dbt command. Add ordered steps in the schedule builder and they execute one after another within the same run, so you can build, test, and generate docs in a single job without wiring up separate schedules.
- The first command is always step 1; add as many follow-up steps as you need
- Steps run in the order you list them, sharing the same environment and dbt version
- The run stops at the first failing step, so a failed build never masks a later step's result
- Steps can include
dbt source freshness, so you can check that upstream data is current before the rest of the pipeline runs - Each step shows its own status chip (queued, running, passed, failed) on the run, so a multi-step job tells you at a glance exactly which command it is on and which one failed. Run logs are color-coded, and the run summary shows the target environment the job ran against
- Opening the log of a run that has already finished waits for the full output rather than showing you an empty panel, so the log of a job that failed overnight is there when you go looking for it
Dependency Chains
Chain whole jobs together with run after: pick another job in the same project, and a successful run of that job automatically enqueues this one. dbdeux validates the chain so you cannot point a job at itself or create a cycle.
Create pipelines where one job triggers the next:
- Extract job runs at 6:00 AM (seeds and sources)
- Transform job starts when extract succeeds (staging + intermediate models)
- Serve job starts when transform succeeds (marts and final models)
- Test job runs after serve to validate data quality
If any job fails, downstream jobs are held and you are notified immediately.
Monitoring
Recent Runs
View the complete history of scheduled runs with full filtering and sorting:
- Status filter: Show only successful, failed, skipped, or in-progress runs
- Trigger filter: Filter by trigger type (scheduled, manual, merge, API). Runs started by a service account or AI assistant are labelled API, so an unexpected run is never mistaken for one a person clicked
- Environment filter: narrow the list to a specific environment, or to an environment type (development, sandbox, pre-production, staging, production, post-production, custom). Answering "did anything fail in production today?" no longer means scanning every run
- Combined search: one search box matches across job name, tag, project, environment, and the person who triggered the run, so you can find a run from whatever detail you happen to remember
- Sortable columns: Click any column header to sort by status, trigger, attempt count, created time, or duration, and click again to reverse the order
- Resizable columns: Drag a column edge to give a long job name or environment the width it needs. Values that still do not fit are cleanly truncated rather than breaking the table layout
- Pagination: Browse through results 15 at a time with page counts
- Duration comparison against historical averages
- Sticky header: The column headers stay fixed while you scroll through long run histories
- Error details for any failures with direct links to logs
Recent History and the Run Archive
Recent history keeps every finished run for at least 90 days, and longer on higher plans (up to a full year; your organization's allowance is listed on Plan & Limits). Runs older than that do not disappear: they move to a read-only archive.
- Archived runs leave the recent list and the charts, which keeps both fast and focused on what is current
- A link to an archived run still opens it, from a notification, a ticket, or the API. The run is marked Archived with a banner explaining that it is being shown read-only from the archive
- The Logs tab is intact for an archived run, so a "what happened on the 3rd of March" question is answered from the run itself. Per-run test results, source freshness results, and notification attempts are kept for runs in recent history; for archived runs the log and the run artifacts through the API remain the record
- If a link points at a run older than your organization keeps, the message says so, rather than showing an empty page
The practical difference from tools that either purge history or keep everything in one ever-slower list: your day-to-day view stays quick, and the audit trail stays reachable.
Activity
Each job has an Activity tab: every edit to the job and every run it has made, in one timeline, with the person or the API token behind each entry. It is the job's slice of the Audit Log, pinned to that job so you do not have to build a filter, and one click opens the full Audit Log already scoped to the job and its runs. "Who changed the schedule last Tuesday, and what did the next run do" is one screen.
Per-Run Source Freshness and Artifacts
Each run keeps the artifacts it produced so you can inspect exactly what happened after the fact:
- Source freshness tab: when a run checked source freshness, its results are captured per run, so you can see which sources were current at the time and trace a stale-data incident back to the exact run
- Artifact download: download the run's generated artifacts (compiled SQL, manifest, run results) directly from the run detail page for offline inspection or auditing
Health Dashboard
At-a-glance view of all scheduled jobs:
- Which jobs are running now
- Which jobs succeeded or failed recently
- Upcoming scheduled runs
- Average duration and success rate trends over time
- A time range selector for the run statistics: Today, Yesterday, Last 7 days, Last 31 days, Last 60 days, or Last 90 days. Success rate and duration are recomputed for the window you pick, so "how did this week go" and "how does this quarter compare" are the same chart with a different range, and the list below it follows the same window
Alerting
Scheduled runs integrate with Notifications:
- Get alerted on failure (or even on success, if you want confirmation)
- Notify separately when a run's dbt tests fail, even if the run itself reported success
- Notify separately again when a test warned: a test with
severity: warntripped, the run kept going, and you still hear about it. Ideal for freshness checks and data quality signals you want to see without failing the build - Reach the team through Slack, email, or PagerDuty, with organization defaults so a new job is never left unmonitored
- Review every delivery attempt, including the ones deliberately skipped and why, on the job's Notifications tab
Merge Triggers
In addition to cron schedules, jobs can be triggered automatically when code merges to a branch:
- Enable the Merge trigger toggle on any job
- Select the branch to watch (typically your default branch)
- The job runs automatically after each merge, ensuring production is always up to date
- Works with all supported Git providers (GitHub, GitLab, Azure DevOps, Bitbucket)
Jobs for Managed Projects
Projects hosted by dbdeux do not have a Git repository, and scheduled jobs work for them just the same. Instead of cloning a repository, the run uses the project's managed files. Nothing about scheduling, environments, steps, notifications, or run history changes, so a team can automate production builds before they have decided on a repository, and connect one later without rebuilding their jobs.
Multi-Provider Support
Scheduled jobs work seamlessly across all supported Git providers. When a job triggers, the platform clones your project repository from the correct provider using stored credentials:
| Provider | Clone method | Branch resolution |
|---|---|---|
| GitHub | OAuth / Personal Access Token | Automatic default branch detection |
| GitLab | Personal Access Token | Automatic default branch detection |
| Azure DevOps | Personal Access Token | Automatic default branch detection |
| Bitbucket | App password | Automatic default branch detection |
If your project was created before default branch detection was available, the scheduler automatically resolves the correct branch from your provider.
Finding a Job
The job list groups jobs by the environment they target, with jobs that have no environment gathered under their own heading, so a long list reads as a small number of understandable groups rather than one flat wall of names. Pick an environment from the selector above the list to see only that environment's jobs. The list tells you plainly when a group is empty rather than looking broken.
Clone a Job
Clone creates a copy of a job with the same steps, schedule, and settings, ready for you to adjust. It is the fastest way to stand up a variant of something that already works, for example the same build pointed at a different environment or narrowed to one tag, without rebuilding it step by step and hoping you matched the original.
The copy is created paused. A cloned schedule cannot fire while you are still editing it, so you resume it deliberately once it says what you meant. Cloning selects the new copy and opens it straight in the edit drawer, so the one thing you always want to do next is already done for you.
Manual Triggers
Any scheduled job can also be triggered manually:
- Click Run Now to execute outside the normal schedule
- Useful for backfills, reruns after fixes, or ad-hoc refreshes
- Manual runs appear in the same history alongside scheduled runs
Run now reports its real state as it happens, moving through Submitting, Queued, Preparing, and Running rather than leaving you to wonder whether your click registered. While a run is in flight the button is unavailable and says so, so nobody accidentally starts the same build twice.
Maintenance Mode
Sometimes you need the schedule to stop for a while: you are merging a large model change, your warehouse has a maintenance window, or an upstream loader is republishing history. Maintenance mode pauses a whole workspace's jobs in one action instead of asking you to disable each one and remember to turn them all back on.
Turn it on from the Jobs page, give the reason your teammates will see, and choose how long it should last. While it is on:
- Scheduled, chained, and merge-triggered runs are recorded as Skipped rather than quietly not happening, so the gap in your history is explained
- Manual, API, retry, and backfill triggers are refused with the reason you wrote, so nobody is left guessing why their run will not start
- Runs already in progress are never cancelled. Turning maintenance mode on is safe mid-build
- Every job shows a Frozen marker, and both the Jobs and Runs pages carry a banner naming the reason and when it ends
- A workspace owner or organization admin can still force a single urgent run from Run now, after an explicit confirmation, and that override is recorded
Pick a duration and leave turn off automatically enabled, which is the default we recommend, and the freeze ends on its own. A forgotten freeze is the failure mode that actually hurts: it is the reason people avoid pausing anything and disable jobs by hand instead, then discover a week later that half the schedule never came back. Jobs resume on their next normal trigger, with no catch-up storm.
Both turning maintenance mode on and turning it off are recorded in the audit log, along with every attempt that was blocked while it was on, so "why did nothing run on Saturday?" has an answer with a name and a reason attached to it.
Post-Run Actions
Trigger downstream systems automatically when a scheduled job completes:
Power BI Refresh
Refresh Power BI semantic models after your dbt run finishes:
- Pick the workspace from a list of the workspaces your credential can actually see, by name, then choose the models inside it. There is nothing to look up and paste, and a mistyped identifier cannot silently point at nothing. If the list cannot be loaded, you can still enter the identifier by hand
- Selected targets are shown as chips with readable workspace and model names, so a job's configuration is legible months later. Targets saved before names were available are resolved to their real names when you open the job, rather than leaving you with an identifier to decipher
- Supports multiple workspaces in a single job
- Uses a reusable Integration Credential (service principal) stored centrally on the Integrations page
- Refresh triggers only when the dbt run succeeds
Only Fire When Something Actually Changed
Each action can also be set to run on success with data changes, rather than on every success.
On an environment with state-aware runs, a nightly build where nothing upstream moved reuses its models instead of rebuilding them, and there is nothing new for a dashboard to pick up. Refreshing anyway costs BI capacity and, worse, trains people to ignore the notification that comes with it. With this condition set, the handoff happens on the nights that produced new data and stays quiet on the nights that did not.
API Endpoint
Call any HTTP endpoint when a job reaches a terminal state:
- Configure a base URL with authentication (Bearer token, API key, or Basic auth)
- Stored as a reusable Integration Credential for use across jobs
- Supports automatic retries with linear backoff on transient failures
- Useful for triggering downstream pipelines, Slack bots, or custom webhooks
Configuration
Add post-run actions in the "When this finishes" section of the schedule wizard. If you have not set up a credential yet, the wizard links straight to the Integrations page so you can create one and come back, rather than leaving you with an empty dropdown and no explanation. Each action specifies:
- Which integration credential to use
- Which targets to trigger (datasets, endpoints)
- Whether to wait for completion before marking the action as done
On the job, the configured targets are summarized rather than listed in full, so a job with twelve Power BI models reads as a single line. Hover it and a tooltip names every workspace and model that will be refreshed, so you can confirm the list without opening the wizard.
Did the Handoff Actually Happen?
A post-run action is a handoff to another system, which historically is where visibility ends. Each run now keeps a post-run actions log underneath its output, with one timestamped line per action:
- What fired, and for which workspace, model, or endpoint
- What was skipped, and the reason (no credential attached, no valid target, a saved credential that no longer exists), rather than the action silently doing nothing
- What failed, including the response the other system returned
That means "the dashboard did not refresh" is answerable from the run itself. You can see whether dbdeux triggered the refresh and got a good response, or never triggered it and why, without asking a BI admin to go looking.
Streaming Run Logs
Monitor job execution in real time:
- Logs stream live while the job is running (auto-refreshes every few seconds)
- Full dbt output with syntax highlighting
- Logs persist after completion for debugging and audit
Job Runs Overview
The job detail page includes a visual runs overview chart with a switcher between four views so you can read run health from different angles:
- Build duration: a per-run scatter of how long each run took, to spot slow-downs and outliers
- Success rate: a per-day trend line of the share of runs that succeeded
- Run outcomes: per-day stacked bars breaking runs into succeeded, errored, and skipped
- Runs volume: per-day bars showing how many runs happened
All views share one frame, scale with the page width for readability, and make it easy to detect flaky or degrading jobs at a glance.