WaveHouse

wavehouse.dev · 2026-08-20 · by Long Nguyen ·generic
The open-source real-time API gateway for ClickHouse — schema-aware ingest, async batching, real-time streaming, and tiered query caching in a single binary.

WaveHouse

Open Source · Apache 2.0

WaveHouse

The open-source real-time API gateway for ClickHouse®. Schema-aware ingest, async batching, real-time streaming, and tiered query caching — in a single binary.

Read the docsTry WaveHouse Cloud

$pnpm add @wavehouse/sdk— stars · live

stats.wavehouse.devconnecting…

—stargazers

—forks

—events · 7d

⚡ingested → live— tracked

connecting to the live stream…

Star Wave-RF/WaveHouseand watch it land here, liveFull demo

Queried in your browser by `@wavehouse/sdk` — one cached `pipe()`summary, a server-curated `pipe()` backfill, and a live SSE`stream()`.

1binaryAPI · worker · NATS · dedup

< 100mswarm-cache query path, local bench

SSEstreamingreal-time push, gap-filled from history

Apache 2.0opensame binary, self-host or managed

Why WaveHouse exists

Section titled “Why WaveHouse exists”

ClickHouse is a phenomenal OLAP database, but pointing a frontend straight at it comes with sharp edges: custom APIs, Kafka® queues to avoid “too many parts” errors, replacing-merge logic for deduplication. WaveHouse abstracts all of that into a single, deployable binary so you stop interacting with ClickHouse directly.

Frontend → ClickHouse, directly

  • One insert per event → Too many parts, HTTP 500 under load
  • No backpressure, no edge validation — bad rows fail late
  • No real-time push — poll every 2s or bolt on Kafka + WebSockets
  • No row/column security — hand-write tenant filters on every query
  • →

    Frontend → WaveHouse → ClickHouse

  • Async WAL + batched flush — never “too many parts”
  • Schema-validated at the edge, 503 + Retry-After under load
  • Native SSE push, gap-filled from history — no extra stack
  • Hasura-style JWT row/column policies, built in
  • If you’re building user-facing analytics, WaveHouse is like Supabase™ for ClickHouse — or an open-source Tinybird™ that pushes data to the frontend in real time over SSE, not just via pull-based REST.

    Schema-aware validation

    WaveHouse discovers your ClickHouse schemas via `system.columns` and validates every ingest against the real schema — unknown fields, type mismatches, and null violations are rejected at the edge.

    Async buffered ingest

    Writes land in a durable NATS™ JetStream WAL and return `200 OK` instantly. A background worker batch-flushes to ClickHouse — never drop a packet.

    Real-time push

    Every event is broadcast to SSE subscribers before it’s flushed to ClickHouse. Gap-fill from JetStream history for late-connecting clients.

    In-process query cache

    Ristretto cache plus Go `singleflight` coalesces identical concurrent queries — dashboards survive thundering herds without an extra cache tier to operate.

    Hasura-style access control

    Per-table, per-role column and row-level policies with JWT claim templating. Stored in NATS KV with file-based bootstrap and cluster sync.

    TypeScript SDK

    `@wavehouse/sdk` — a type-safe query builder, live queries, real-time streaming, and codegen from your schemas, with one runtime dependency of \~1.4 KB gzipped.

    Plus — optional deduplication (idempotent ingest by ID), a dead-letter queue for failed batch inserts, and Tinybird-style named pipes with parameter binding and per-role restrictions.

    Query it like a database. Subscribe to it like a socket

    Section titled “Query it like a database. Subscribe to it like a socket”

    The TypeScript® SDK wraps the whole surface — typed inserts, a chainable query builder, and live queries that backfill history before streaming:

  • Ingest
  • Query
  • Live updates
import { createClient } from '@wavehouse/sdk';
const wh = createClient({ baseURL: 'https://<project_id>.wavehouse.app' });
// Returns immediately — buffered in the WAL, schema-validated// at the edge, batch-flushed to ClickHouse behind the scenes.await wh.from('clicks').insert({ page: '/home', button: 'signup' });
// Chainable, type-safe, never throws — branch on { data, error }.const { data, error } = await wh.from('clicks')  .select('page', 'button', 'score')  .where('page', '=', '/home')  .orderBy('received_timestamp', 'desc')  .limit(100);
// Historical backfill, then the live stream.const lq = wh.from('clicks')  .selectAll()  .where('page', '=', '/home')  .orderBy('received_timestamp', 'desc')  .limit(100)  .liveQuery({    initial: (result) => setRows(result.data ?? []),    next: (event) => addRow(event.data),  });
// later: lq.close();

Up in five minutes

Section titled “Up in five minutes”

One compose file — ClickHouse + WaveHouse — and you have an ingest endpoint, a query endpoint, and a live event stream:

# Boot ClickHouse + WaveHouse with one compose filegit clone https://github.com/Wave-RF/WaveHouse.gitcd WaveHousedocker compose -f deployments/compose/standalone.yaml up -d

Ingest an event (run Getting Started first to create the `clicks` table; the dev stack ships a trial policy)curl -X POST "http://localhost:8080/v1/ingest?table=clicks" \ -H 'content-type: application/json' \ -d '{"page":"/home","button":"signup","score":42.5}'

Subscribe to the live streamcurl -N "http://localhost:8080/v1/stream?table=clicks"

WaveHouse is fail-closed, so the standalone stack ships a permissive trial policy (a non-admin `public` role that can read/write the demo tables, seeded on first boot) — then it’s five minutes from `git clone` to a live event stream. See Getting Started.

How it ships: one `wavehouse` process — API, batch worker, embedded NATS JetStream, and optional embedded Pebble dedup, all in-process. The only external dependency is ClickHouse. Same binary on a laptop, in Docker®, or on a production host.

Or skip the ops entirely

Section titled “Or skip the ops entirely”

Self-hosting WaveHouse is deliberately boring — one binary, one dependency. But that one dependency is a ClickHouse cluster somebody has to size, upgrade, back up, and keep alive at 3am.

Where to next

Section titled “Where to next”

Getting StartedFive-minute quickstart — Docker Compose, first ingest, first query, first stream.

ArchitectureSystem design, ingest/query/streaming data flows, and the internal package map.

API ReferenceEvery endpoint, authentication, and request/response format.

TypeScript SDKQuery builder, live queries, streaming, and schema codegen.

WaveHouse is alpha — and built entirely in the open.

Apache-2.0-licensed, single binary, no vendor lock-in — self-host it forever, or let us run it on WaveHouse Cloud. We ship with honest expectations — see the support cadence and security policy. Kick the tires and tell us where it breaks.

Get started in five minutesStar on GitHub

★ — and counting — counted live by WaveHouse

wavehouse.dev · 24 links

Comments (0)

No comments yet