> Documentation index: https://docs.beetl.io/llms.txt

# Reports

> PDF documents built from your data, on demand or on a schedule.

Source: https://docs.beetl.io/reports/
Last updated: 2026-10-28

A report is a PDF layout bound to SQL over your datasets. Each run reads the current data, fills
the layout and stores the result as a document you can view, download and tag. Reports belong to
the workspace, so every user in the tenant sees the same reports, templates and documents.

Reports need an object store configured for the tenant. Without one, saving a report fails with
`OBJECT_STORE_NOT_CONFIGURED`.

## Create a report

You create and change reports through the assistant. The **Reports** page in the sidebar lists
them on a **Reports** tab and a **Templates** tab, but it has no editor.

    ### Ask the assistant [#ask-the-assistant]

    Open AI Chat and describe the document: what it should show, which datasets it reads and how it
    should look. For example, "a one-page monthly supplier summary with a table of the ten largest
    open invoices". See [Building with the assistant](https://docs.beetl.io/chat/building-with-the-assistant).

    ### Check the preview [#check-the-preview]

    The assistant shows the rendered report in the chat's artifact pane. Ask for changes until the
    layout is right.

    ### Save it [#save-it]

    Saving renders one document first, so SQL errors and layout errors are rejected with diagnostics
    and nothing is stored. The assistant reads the diagnostics and fixes the report.

A report appears as a node on the Home graph, with a Reads edge from each dataset it uses. Click
the node to open its details. See [Data landscape](https://docs.beetl.io/query/data-landscape).

An MCP client with a `write` key can create and change reports too, using `create_report` and
`update_report`. Reports write PDFs to your tenant's storage, so give `write` keys only to people
and tools you trust with that. See [Tool reference](https://docs.beetl.io/mcp/tool-reference).

## Run and schedule

A report runs in three ways:

* **Run now** on the report's page.
* Through the assistant in chat.
* On a schedule: a cron expression with a time zone. A report cannot run more often than every 15
  minutes, and saving fails if the schedule would.

A run shows how many documents were issued and how many failed. A report runs one at a time: if
you start a run while one is in progress, you get `REPORT_ALREADY_RUNNING`. A run cannot be
cancelled once it has started.

## Per-row reports

A whole report issues one document per run. A per-row report issues one document for each value of
a key column that a query returns, such as one statement per customer.

* Each key value is issued once. Later runs only issue documents for new key values.
* Keys that already exist when you create the report count as issued, unless you ask for a
  backfill, which issues documents for them too.
* A document that failed is tried again by the next run.

Per-row queries return at most 10,000 rows, and a key can be at most 1,024 bytes.

## Archive and tags

The report's page lists its documents. Search them by label or tag, open one page by page, or
download the PDF. Tag a document to find it later; a document can hold up to 20 tags of up to 64
characters each. Setting tags replaces the previous set.

Documents are kept until the report is deleted. Deleting a report deletes its documents.

## Templates and images

A template is a reusable layout that reports import, so a letterhead or table style lives in one
place. Templates and images are shared across the tenant. Charts are supported in layouts.

* A workspace can hold up to 50 templates.
* Images can be PNG, JPEG, WebP or SVG, up to 2 MiB each, with up to 20 per report or template.
* Deleting a template stops every report that imports it from running, so check which reports use
  it first, for example by asking the assistant.

Template names use lowercase letters, digits and hyphens, up to 64 characters.

## Automations that render PDFs

An [automation](https://docs.beetl.io/automations) can turn its finding into a PDF. Choose a **report template** in the
automation's definition. After a run completes, its page offers the PDF with a per-page view, and a
**PDF** and **Summary** toggle. If the PDF is missing, choose **Render PDF**, or **Retry render**
after a failed render.

Only a completed run can be rendered. A run that failed or is still in progress returns
`AUTOMATION_RUN_NOT_COMPLETED`, an automation without a template returns
`AUTOMATION_HAS_NO_TEMPLATE`, and a template name that does not exist is refused when you save, with
`REPORT_TEMPLATE_NOT_FOUND` on the template field.

## If a run fails

Open the report's page and read the latest run, which shows how many documents were issued and how
many failed. Failed per-row documents are tried again on the next run. A failed
scheduled run shows only in the Runs list, so check it there, or poll `list_report_documents` over
MCP.

| Code                                           | Meaning and what to do                                                                         |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `REPORT_INVALID`                               | The SQL or the layout does not work. Read the diagnostics, which name the binding that failed. |
| `REPORT_CONFLICT`                              | The report changed while your request was running. Try again.                                  |
| `REPORT_ALREADY_RUNNING`                       | A run is in progress. Wait for it to finish.                                                   |
| `REPORT_TEMPLATE_LIMIT`                        | The workspace holds 50 templates. Delete one you no longer use.                                |
| `REPORT_ASSET_TOO_LARGE`, `REPORT_ASSET_LIMIT` | An image is over 2 MiB, or the report or template already has 20.                              |
| `NO_RUNNER_AVAILABLE`                          | Nothing was free to render the report. Try again shortly.                                      |
| `OBJECT_STORE_NOT_CONFIGURED`                  | The tenant has no object store. Configure one first.                                           |

The full list is in [Error codes](https://docs.beetl.io/reference/error-codes).

## Limits

| Limit                     | Value                                     |
| ------------------------- | ----------------------------------------- |
| Layout source             | 256 KiB                                   |
| Bindings per report       | 10                                        |
| Rows per binding          | 10,000                                    |
| JSON per binding          | 8 MiB                                     |
| Per-row query             | 10,000 rows, 8 MiB, key up to 1,024 bytes |
| Pages per document        | 100                                       |
| PDF size                  | 25 MiB                                    |
| Time to render a document | 30 seconds                                |
| Schedule                  | At most once every 15 minutes             |
| Templates per workspace   | 50                                        |
| Images                    | 2 MiB each, 20 per report or template     |
| Tags per document         | 20, up to 64 characters each              |
| Documents                 | Kept until the report is deleted          |

Other limits are listed in [Limits](https://docs.beetl.io/reference/limits).
