# DuckDB recipe

URL: https://briq.cloud/cookbook/duckdb

> Reports on DuckDB: load a dataset from a URL, write dashboards in SQL (Shaper), share a link to one. One briq; the first chart in under a minute.

Tags: app, analytics, database

Guide:

- [Report on a dataset](https://briq.cloud/docs/guides/report-on-a-dataset.md): Load a public dataset into DuckDB, chart it in SQL, and share a link to the dashboard.

## Run it

briq.yaml:

```yaml
stack: app
services:
  duckdb:
    recipe: duckdb
    # its defaults, each a field you can set:
    # image: taleshape/shaper:0.25.2
    # size: nano
    # volume: { gb: 5 }
```

MCP:

```ts
briq_run({ recipe: "duckdb", wait: true })
```

REST:

```bash
curl -X POST https://api.briq.cloud/v1/briqs \
  -H "Authorization: Bearer $BRIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe": "duckdb",
    "wait": true
  }'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "SHAPER_URL": "…" }, … }

# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/<id> \
  -H "Authorization: Bearer $BRIQ_API_KEY"
```

## Fields

Set them beside `recipe`, in briq_run or a briq.yaml service, as a GitHub Actions service.

| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `image` | string | — | "taleshape/shaper:0.25.2" | The image: another tag, or a compatible image (as for a GitHub Actions service) |
| `env` | record | { key: string \| { secret, value?, scope?, hosts?, locations? } } | {} | Added to the recipe's env, or replacing one of its values. A credential as { secret: NAME, value } |
| `cmd` | string \| string[] | — | — | The command: a string run with sh -c, or the argv. Default: the recipe's |
| `size` | enum | nano, small, medium | "nano" | nano for datasets up to a few million rows; small or medium for more, since DuckDB works in memory and spills the rest to disk |
| `volume` | object | { gb? } | {"gb":5} | The volume: { gb } |
| `files` | record | { key: string \| { base64 } } | — | Boot files, added to the recipe's |

## Outputs

Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.

| Output | Value |
| --- | --- |
| `SHAPER_URL` | `http://duckdb.<stack>.internal:5454` |
| `SHAPER_ADMIN_EMAIL` | `admin@shaper.local` |
| `SHAPER_ADMIN_PASSWORD` | `<SHAPER_ADMIN_PASSWORD>` |

## What it runs

| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| duckdb | `taleshape/shaper:0.25.2` | 5454 | nano | 5 GB at /data |

## When to use it

* The agent has a dataset to analyse, and you would rather open charts than read a table in chat.
* You want a dashboard someone can open from a link, without an account.
* You want SQL over CSV, Parquet or JSON files, kept and run again on fresh data.

One briq: [DuckDB](https://duckdb.org) inside [Shaper](https://taleshape.com/shaper/docs/), an
open source dashboard tool where a dashboard is a SQL file. On first boot Shaper makes its admin
account (password in `SHAPER_ADMIN_PASSWORD`). The data lives on the briq's volume. The full
walk-through, from a CSV on the web to a shared link, is
[Report on a dataset](https://briq.cloud/docs/guides/report-on-a-dataset).

## Tips

* **`shp` runs everything** from `briq_exec` on the `duckdb` briq: `shp sql`, `shp dashboard`,
  `shp update`, `shp share`, `shp pdf`, and `shp api` for the rest of
  [Shaper's API](https://taleshape.com/shaper/docs/api-endpoints/). `-` reads SQL from `stdin`.
* **Load from the URL**: `shp sql "CREATE TABLE t AS FROM read_csv('https://…')"`. DuckDB downloads
  the file itself, so the data never goes through the agent. `read_parquet` and `read_json` too.
* **Check with SQL**: `shp sql "SUMMARIZE t"` prints each column's type, range and nulls.
* **A dashboard is SQL**: each `SELECT` is a chart, a table or a value. Casts say how to draw it:
  `x::XAXIS, n::BARCHART, kind::CATEGORY`. The full list is the
  [dashboard SQL reference](https://taleshape.com/shaper/docs/dashboard-sql-reference/).
* **Years on an x axis** draw as dates: `make_date(year::INT, 1, 1)::XAXIS`.
* **Share one dashboard**: `shp share <id>` prints `/view/<id>`. Run with `expose: "private"` and keep
  the `?briq_token=` on the link you send, so the link is the only way in.
* **A PDF to attach**: `shp pdf <id> /tmp/report.pdf`, then `briq_files_get`. For a download button
  on the page: `SELECT 'Report'::DOWNLOAD_PDF AS "Download PDF";`.
* **More data, more memory**: DuckDB takes half the machine and spills the rest to the volume. Use
  `size: "small"` or `"medium"` for a dataset bigger than the nano's memory.
