Module

Lakehouse

An analytical tier for your event and telemetry tables. One Zod object is the whole table definition, exactly as it is for D1 — and from it Pithy derives the Pipelines stream schema, the Iceberg table, the write codec and the query types.

@pithy-sh/lakehouse

Built for Enterprise
Read the docs Source on GitHub

What it is for

D1 is the transactional tier, and it is the wrong shape for event data: append-only, high volume, queried by range and aggregate. Gameplay events, request telemetry and ledger history have nowhere in the kit to go.

Cloudflare already ships the pieces — R2 Data Catalog for storage, Pipelines for ingest, R2 SQL to query across them. Wiring them together is the part that is missing, and wiring is what Pithy is for.

What it sits on

R2 Data Catalog, Pipelines and R2 SQL.

There is no write binding for the catalog, so writes reach it as stream, pipeline, sink — and the sink is what creates the table. The capability owns that whole lifecycle, because a sink cannot adopt a table something else made.

The read path is R2 SQL and is read-only: no inserts, no updates, no DDL. The query builder has no mutation half, by design.

  • R2 Data Catalog
  • Pipelines
  • R2 SQL

The honest bit

It is designed and open. None of it exists yet.

Two platform constraints are why this is a capability rather than a snippet: a stream's schema is immutable once created, and a sink cannot target an existing table. Wire it by hand and the first added field leaves you with a dead table and no path forward.

Until it ships, event data belongs in D1 and you should expect that to get uncomfortable at volume. Saying so is more useful than a date.

If you build it yourself

Two platform constraints make the naive version worse than useless.

The pieces exist. Wiring them wrongly leaves you with a dead table.

A stream schema is immutable

Once created it cannot change, so the first added field breaks a hand-rolled pipeline permanently.

A sink cannot adopt a table

Creation has to happen through the sink, which rules out the obvious approach of making the table first.

The write path is not a binding

There is no direct write to the catalog: it is stream, pipeline, sink, and something must own that lifecycle.

Read-only queries

No inserts, updates or DDL — a query builder with no mutation half, which is not what any ORM expects.

No local development story

Without one, the only place to test is production.

Designed and open. None of it exists yet — which is the honest reason it is on this page at all.

In the dashboard

Administer it from a browser, without building the screen.

Nothing yet. When it ships, the tables it provisions and the schemas behind them will be readable like everything else.

The dashboard is the admin interface for your own application: whatever this capability writes, your team can look up, check and act on from a browser. Reading is free, forever, with no time limit. Connect the project when you deploy.

Add it, and get on with the feature.

One command installs the package, wires its bindings into every environment your project declares, and runs its migrations.