Download all docs

Recipe: Scheduled Report Pipeline

This recipe produces a report on a timer and delivers it to your team. A schedule fires on a cron expression, a sql or timeseries query pulls the numbers, a document renders them into a readable page, and an email or slack step sends it out — every morning, with no one pressing a button.

The problem it solves

Recurring reports are the classic “someone runs a query and pastes it into an email on Mondays” task. It is easy to forget, easy to do inconsistently, and impossible to audit. This recipe makes the whole chain a declarative pipeline: the schedule guarantees it runs, the query guarantees the same numbers, and the delivery step guarantees it lands in the same place every time.

Elements

ElementRole
scheduleFires the pipeline on a cron expression.
sql / timeseriesPulls the report data — relational rows or time-bucketed metrics.
documentRenders the results into an HTML/markdown report page.
email / slackDelivers the finished report.
automationSequences query → render → deliver as one flow.

Flow

  1. Create a schedule. Set spec.cron to your cadence (e.g. 0 0 8 * * * for 8am daily); it emits a schedule event downstream when it fires. Use trigger_now to dry-run the pipeline without waiting, and next_runs to confirm the upcoming fire times.
  2. Pull the data. For relational reporting, use the sql element’s query operation with bind parameters. For metrics over time, use the timeseries element’s query (aggregated) or range (raw points), or downsample for a rolled-up series.
  3. Render the report with a document: write the results into a markdown page, then render it to HTML (markdown plus tables, code highlighting, and math).
  4. Deliver it. Use the email element’s send (or send_tracked for open/click events) to mail the report, or the slack element’s send to post it to a channel.
  5. Tie the chain together in an automation, which references schedule, sql, timeseries, document, email, and slack as steps. The schedule event starts the run; the rest follow as ordered steps.

What this shows

Each stage is a real element doing the one thing it is good at: the schedule owns when, the data elements own what, the document owns how it reads, and the connector owns where it goes. Swap monthly for daily by editing one cron field; switch delivery from email to Slack by re-pointing one step — the query and the rendering do not change. Because the pipeline is declarative, “did the report run?” is answerable from the schedule’s history, not from someone’s memory.

Next pages