Beetl Docs
Getting started

Quickstart

From an empty tenant to a query returning rows.

One path from a brand new tenant to a SQL result. No alternatives, no branches. Upload a CSV, query it, read the rows.

Budget about ten minutes, and read the prerequisite first, because it is the step that stops everyone.

Before you start: the object store

A new tenant is provisioned with no object storage at all. Beetl stores nothing until someone registers a bucket for it. Until that happens, ingest, dataset creation, pipeline destinations and runner dispatch all fail with the same error:

422 OBJECT_STORE_NOT_CONFIGURED

Registering a store is TenantAdmin-only

Object store registration lives at Settings → Tenant, and the three mutating endpoints on that tab require the TenantAdmin role. It is the only role gate in the product. If the first person to sign in to a new tenant is a TenantUser, they cannot get past this step and there is no in-product way around it. Have a TenantAdmin do step 2, or make the first user one.

Sign in

Go to /web/login and press Sign In. Beetl authenticates through Zitadel using an OIDC authorization-code flow with PKCE, so there is no password field anywhere in the product. You land on the Data Landscape graph, which is empty.

Register an object store

Open the account menu, choose Settings, and select the Tenant tab. Register your S3-compatible store with its name and base URL.

Beetl validates it with a live round-trip: it writes an object, reads it back, and deletes it. A store that fails validation is not registered. The first store you register is automatically promoted to the tenant default, which is what every dataset created from here on will be written against.

Open the Connections page

Go to /web/connections.

Connections is not in the navigation

/web/connections is a fully built page family that nothing links to. The August 2026 UI overhaul cut the sidebar down to Home, Chat, Automations, Dashboards and Query, and the Data Landscape graph does not link to it either. You have to type the URL. This is a known gap, not a hidden feature.

Upload a file

Choose New Connection, then File Upload, and drag in one CSV. Accepted formats are .csv, .parquet, .json, .jsonl and .ndjson. Anything else is rejected loudly rather than stored as an opaque blob. The per-file limit is 64 MiB.

Give the dataset an explicit name. Beetl suggests one from the filename, but the name you type is the one that sticks, and it is what you will write in SQL.

One uploaded file becomes one File connection and one Bronze dataset. That relationship is 1:1 by design, and deleting the dataset later deletes the connection with it.

Confirm the dataset exists

Go to /web/data-sets.

The Data Catalog is not in the navigation either

/web/data-sets has the same problem as /web/connections. The page resolves, it works, and nothing links to it. Type the URL. The richer dataset view, with the full Arrow schema, partition columns, storage location and a ten-row preview, lives on the Data Landscape graph instead: open Home, find the dataset node, and expand it in place.

Your file should be listed with a Bronze tier dot, a version badge, and an Active status.

Query it

Click Query in the sidebar. This one is linked.

Write SQL against the dataset name you chose in step 4. Column autocompletion is driven by the real schema, so start typing a column name and Beetl will offer the rest.

SELECT *
FROM your_dataset_name
LIMIT 100;

Execute with the button in the editor footer or Ctrl/Cmd+Enter. The editor uses the DataFusion engine with the PostgreSQL dialect enabled. A run that takes too long can be cancelled from the editor footer.

You now have rows.

Keep the result

The result is not screen state. It is a durable artifact with its own URL, written as Arrow IPC to your object store with metadata in Postgres:

/web/query-results/{result_id}

Flip to Chart to plot it, click a cell to see the column's role and the expression behind it, download CSV, or reopen it later from the Recent results dropdown in the page header.

Results expire after 7 days

Default retention is seven days. There is no pin, no save-as-report, and no warning before it goes. An expired result opens as an explicit "Result expired" state. If a number matters beyond a week, export the CSV or put the query behind a pipeline that writes a dataset. Full detail on Query results.

Next: your first pipeline

A pipeline turns that query into something that runs repeatedly and writes a dataset instead of a seven-day artifact. Start at /web/pipelines, add your Bronze dataset as a source, paste the SQL you just ran as the first stage, preview it, add a destination, then Save and Deploy.

Pipelines is not in the navigation

/web/pipelines is the third built-but-unlinked page family. Type the URL, or right-click the Data Landscape canvas and choose New pipeline, which opens the same editor.

The full tour is in Pipelines. If you hit an error code along the way, the first-run traps page collects the ones people actually hit.

On this page