Beetl Docs
Core concepts

Query results

Addressable artifacts, and the 7-day clock on them.

A query result in Beetl is not screen state. It is an artifact with an identity, a URL, a storage location, and an expiry date. Understanding all four saves you from the one mistake everybody makes with them.

What a result actually is

When you run a query, the server reserves a result id before dispatching anything. A runner executes the SQL and writes the output as an Arrow IPC file to your object store, under query-results/{tenant_id}/{result_id}.arrow. The metadata, including row counts, execution time, the SQL, and a lineage profile, goes to Postgres.

The browser never touches Arrow. It reads JSON envelopes from the API and renders the table and the chart itself.

The result is addressable:

/web/query-results/{result_id}

with sibling routes for the pieces built on top of it:

/web/query-results/{result_id}/chart-options
/web/query-results/{result_id}/drill
/web/query-results/{result_id}/csv

Rows page through the same endpoint with offset and limit. The table view fetches 100 rows at a time as you scroll, up to 50,000.

The seven origins

Every result records where it came from. QueryResultOrigin has seven variants, and they all produce the same kind of artifact:

OriginProduced by
Ad-hocA query you ran in the Query editor.
Pipeline previewPreviewing a single SQL stage in the pipeline builder.
ChatThe assistant calling execute_query during a conversation.
MCPAn external client, such as Claude or Cursor, calling execute_query over MCP.
Drill-downClicking through from a cell to the rows behind a value.
APIA programmatic caller.
AutomationA scheduled automation run, where the result becomes the evidence behind its report.

This matters more than it looks. A number the assistant quotes in chat, a number in an automation report, and a number you got by hand are all backed by the same inspectable artifact. You can open any of them, page the rows, and check.

Ownership and scope

Results are creator-owned and tenant-scoped. You see your own; nobody else in the tenant sees them unless they run the query themselves.

There is no sharing model and no shareable link. Sending a colleague a result URL does not give them access to it. If a result needs to reach someone else, export the CSV or put the query behind a pipeline that writes a dataset a dashboard can read.

Retention

Results expire after 7 days, silently

Default retention is seven days from creation. There is no pin, no save-as-report, no favourite, and no warning before an artifact goes. Opening an expired result shows an explicit "Result expired" state rather than an error, which is the first many people hear about it. If a number has to survive a week, it needs a pipeline behind it or a CSV in your hands.

The Recent results dropdown in the Query page header holds your ten most recent ad-hoc results with their SQL, row counts and creation time. It is a convenience, not storage. Those entries die on the same clock as everything else.

Chart specifications are not persisted at all. Rebuilding the same chart on a result means picking the type and axes again, and the chart disappears with the result. Saved, shareable visuals live in Dashboards instead.

The consequence for automations

An automation report persists. Its evidence does not.

Each automation run writes a Markdown report and links every query it executed to the durable result behind it. The report is durable. The query results it points at expire on the ordinary seven-day clock. An automation report older than a week is therefore a set of conclusions whose evidence links have gone dead.

That is a known and documented consequence, not a bug you are the first to hit. Until retention policy changes, treat an old report as a claim to re-verify rather than a record to cite. See Automations.

What does not expire

Datasets. A pipeline destination writes a Delta table that stays until you delete it, with version history behind it. That is the correct home for anything you intend to look at repeatedly, and the right answer to "can we keep this result" is almost always "make it a pipeline".

One footnote for completeness: results fetched over Arrow Flight SQL, which is how embedded Superset dashboards read tenant data, are transient rather than durable. They are swept every five minutes with a fifteen-minute retention, and they never get a result id at all.

On this page