# How to schedule SQL reports with the scheduler you already have

> Schedule SQL reports with cron, Airflow, Dagster or Databricks Jobs: named schedules in YAML, a preview of every firing, and reruns that keep their period.

[← All guides](https://getdre.com/guides/)

# How to schedule SQL reports

Most teams already run a scheduler: cron on a server, Airflow, Dagster, Databricks Jobs or GitHub Actions. DRE doesn’t add another one. It keeps the schedule _definitions_ next to the reports, shows when each one fires, and gives your scheduler one command to run, so a report runs on time and a rerun reproduces the original period.

## 1\. Name the schedules next to the reports

`schedules.yml` lives in the project, in git. One report can have several schedules, each with its own variables, and a schedule can follow a group of reports by tag.

schedules.yml

```yaml
- name: flash_daily
  report: sales_summary
  cron: "0 7 * * *"
  timezone: Australia/Sydney
  vars: {period: day}
- name: close_monthly
  report: sales_summary
  cron: "0 6 1 * *"
  timezone: Australia/Sydney
  vars: {period: month}
- name: finance_daily
  select: tag:finance
  cron: "0 7 * * 1-5"
  timezone: Australia/Sydney
```

When many schedules share a timing, such as “the 1st of the month, 06:00 Sydney”, name it once in`timings.yml` (with holidays to skip) and refer to it from each schedule.

## 2\. Check when they fire

`dre schedule ls` works out every firing in a window, so a reviewer can check that a cron expression and timezone mean what the author thinks, before it reaches production.

terminal

```bash
dre schedule ls                                # the next 5 firings of each schedule
dre schedule ls -s sales_summary --limit 10    # when does this report run?
dre schedule ls --output json                  # every firing in the next 35 days, with its command
```

## 3\. Let your scheduler run the command

Whatever the scheduler, the task is one command. Pass the instant the run was scheduled for in `DRE_RUN_AT`, so the report’s dates come from the schedule rather than the clock.

crontab

```bash
# min hour day month weekday
0 6 1 * *  cd /srv/reports && DRE_RUN_AT="$(date -u +\%Y-\%m-\%dT\%H:00:00Z)" dre run --schedule close_monthly --target prod
```

In Airflow, Dagster or Databricks Jobs, run the same command as a task, usually right after the job that refreshes the tables (for example your dbt run), with the run’s logical time as `DRE_RUN_AT`. For a self-hosted setup that loads every firing into a database and runs what’s due, see the [orchestration recipe](https://getdre.com/docs/orchestration/), which DRE’s demo project tests against Postgres.

## 4\. Rerun a period without editing anything

When someone asks for September again because late refunds came in, run the same schedule with September’s instant. The SQL, file names and email subjects render as they did on the day:

terminal

```bash
DRE_RUN_AT=2026-09-30T20:00:00Z dre run --schedule close_monthly --target prod
```

Every run records its schedule, variables and scheduled instant in `run_results.json` and its log, so you can see exactly what ran. (Reproducing the same numbers also needs the source data as it was, if it has changed since.)

## Why not a scheduler built into the reporting tool?

Your scheduler already handles retries, alerts, dependencies and access control, and your team already watches it. Keeping report schedules there means reports run after the data they depend on, failures show up where the other failures do, and there is no second system to secure. DRE’s part is to make the schedule reviewable in git and the run reproducible.

[Schedules in the docs →](https://getdre.com/docs/schedules/)[Automate a report to Excel](https://getdre.com/guides/automate-sql-reports-to-excel/)
