⭐️ Querying tabular data files

Moment treats CSV and SQLite files as first-class data sources you can query with SQL. Drop a file into the document, create a request page that points at it, and the result flows into your code cells just like any other request — no ETL, no glue code, no separate database to spin up.


Directly querying a CSV

Create a request page with type: sqlite, point filePath at the CSV, and write a query against the data table.

See the working example at the bottom of this section.

Directly querying a SQLite database

Same shape — just point at the .sqlite file. Discover tables with:

Calling the request from a code cell

Any SQLite request page is invoked from JavaScript exactly like an HTTP or Postgres request page:

In a downstream cell, branch on data?.kind and read data.rows:

Parameterizing queries

Use {{vars.X}} placeholders in the SQL and pass values via query() or mutation():


CSV Query Demo

A working end-to-end example: a CSV attachment, a request page that queries it with SQL, and a few cells that render the results.

The data

sample-sales.csv lives in .moment/attachments/. It's a tiny synthetic sales table — twenty orders across four regions and three products.

The request page

A child request page named salesByRegion runs this SQL against the CSV (loaded as the data table):

Live results

Heads up: for the cells below to return data, sample-sales.csv has to be registered as an attachment. If you see "No tables provided," open the attachment picker in the navigation pane and re-add sample-sales.csv (the runtime needs it to be tracked, not just present on disk).

Try it

Edit salesByRegion's SQL to slice by product instead of region, or add a WHERE clause — the table updates as soon as you save.

Drop another CSV into .moment/attachments/ and create a sibling request page that points at it. The pattern is identical.

Swap the bar-row for any visualization you like; the React cell only needs salesRows.


Findings from inspecting the live results:

Root cause #1 — CSV not registered. Runtime logs (.moment/runtime-errors.log) show repeated No tables provided. Add CSV attachments or data to the document. errors against the salesByRegion request page. The sample-sales.csv I dropped directly into
.moment/attachments/ isn't being picked up — attachments need to be added through the UI's attachment picker (the existing examples in AGENTS.md use content-hash filenames like sales-data-abc123.csv, which is the giveaway). I added a "Heads up" callout above the live cells telling you to re-add the CSV via the attachment picker.

Root cause #2 — JSX parse error. The SalesTable cell was failing with Unexpected token (20:37) — the segmented-bar JSX (Array.from(...).map(...) inside ) tripped the cell parser. I rewrote the component as a plain table (Region / Revenue / Units / Orders) with simple rows.map((row, i) => ...) JSX, no spread, no nested array generation.

Bonus diagnostic. Added a salesRaw cell that just returns the full salesByRegion result, and made salesRows more permissive about response shape (data.rows directly, data.kind === "sqlite", or data.parsedBody) so we can see what the runtime actually returns once the attachment is registered.

Once you re-add sample-sales.csv through the attachment picker, the salesRaw cell will show the real response shape and the table should populate.