Reports
A report combines a SQL query, a cron schedule, an output format, and one or more delivery channels. DataRunner runs the query on schedule and delivers the output automatically — no infrastructure required.
- Read
- 6 min
- Sections
- 6
- Formats
- CSV · XLSX · PDF · HTML
Creating a report
Go to Reports → New report. The report wizard has four steps:
- Query — select an existing saved query or write one inline
- Schedule — set a cron expression and timezone
- Output — CSV, Excel, PDF or inline HTML; a route can override it per destination
- Delivery — configure one or more channels (email, Slack, S3, webhook)
Save the report and DataRunner schedules it immediately. The first run fires at the next matching cron time. You can also trigger a manual run at any time from the report detail page.
Cron schedules
DataRunner uses standard 5-field cron syntax: minute hour day-of-month month day-of-week. The schedule editor has a visual builder if you're not familiar with cron expressions.
| Expression | Meaning |
|---|---|
| 0 8 * * 1-5 | Every weekday at 8:00 AM |
| 0 9 * * 1 | Every Monday at 9:00 AM |
| */15 * * * * | Every 15 minutes |
| 0 0 1 * * | First day of each month at midnight |
| 0 9 1-7 * 1 | First Monday of each month at 9:00 AM |
| 0 */6 * * * | Every 6 hours |
| 30 17 * * 5 | Every Friday at 5:30 PM |
Schedules run in the timezone you specify. DataRunner converts to UTC internally. If you change the timezone on an existing report, the next run fires at the next matching time in the new timezone.
Output formats
The report's format decides how the result set is turned into the attachment or payload a route delivers. A route can override the report-level format, so the same run can go out as one shape to Slack and another to S3.
CSV
The portable default — opens anywhere, and the right choice when something downstream is going to parse it:
- Comma-separated, UTF-8 encoded
- Column headers taken from the query’s SELECT column aliases, written as the first row
- Values containing a comma, a double quote, or a newline are quoted, with inner quotes doubled
- Delivered as <report name>.csv with a text/csv content type
Excel (XLSX)
A real workbook rather than a CSV with a different extension — pick it when a person, not a script, opens the file:
- Typed cells: numbers stay numeric, booleans stay boolean, and timestamps become real date cells so sorting and filtering behave
- A value that merely looks date-ish (a product code like 2026-1) is kept as text rather than silently converted
- SQL NULL becomes an empty cell, not the word "null"
- Bold header row, frozen so it stays visible while scrolling, with an autofilter over the range
- Columns auto-sized to their contents
A paginated landscape document, for a report that gets read rather than filtered:
- Title block with the row count and the generation timestamp
- The header row repeats on every page, so page 7 is readable on its own
- Alternating row shading and a "Page n of m" footer
- Values too wide for their column are truncated with an ellipsis rather than bleeding into the next one
- Capped at 5,000 rows and 12 columns — past that a PDF stops being the right container; use CSV or XLSX
Inline HTML
Renders the result as an HTML table in the message body instead of attaching a file — for a short digest someone should be able to read without downloading anything. The table is also exposed to email templates as {{result_table}}, so a template can show a preview alongside an XLSX attachment. Capped at 500 rows.
Delivery channels
A report can have multiple delivery channels. DataRunner sends to all of them on every run. Configure channels on the Delivery tab of the report detail page.
Send to any email addresses with a custom subject line and body. Attach the report file. Configure SMTP or a transactional API (SendGrid, Mailgun, etc.) in Settings → Email. Use broadcast lists to define reusable recipient groups.
Post a message or file to any Slack channel or DM. Configure a Slack integration in Settings → Channels. Customize the message body with the report name, run time, and row count using template variables.
Upload the report file to any S3-compatible bucket. Configure the bucket, region, and credentials in Settings → Channels. The file path supports template variables: {{report_name}}, {{date}}, {{time}}.
POST a JSON payload to any HTTP endpoint after each run. Configure custom headers and an auth token. The request body includes the report name, run timestamp, row count, and a download URL for the output file (valid for 24 hours).
Run history
Every report has a Run history tab showing all past executions. For each run:
- Timestamp and trigger type (scheduled or manual)
- Duration (query execution time + delivery time)
- Row count of the result set
- Status per delivery channel (delivered, failed, pending)
- Download link for the output file
- Full error message if the run failed