Skip to content
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.

stats.wavehouse.dev connecting…
stargazers
forks
events · 7d
ingested → live

    connecting to the live stream…

    Star Wave-RF/WaveHouse and watch it land here, live Full demo ↗
    1binaryAPI · worker · NATS · dedup
    < 100mswarm-cache query path, local bench
    SSEstreamingreal-time push, gap-filled from history
    Apache 2.0openno vendor lock, no SaaS tier

    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 — zero-dependency client with type-safe query builder, live queries, real-time streaming, and codegen from your schemas.

    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 zero-dependency TypeScript SDK wraps the whole surface — typed inserts, a chainable query builder, and live queries that backfill history before streaming:

    import { createClient } from '@wavehouse/sdk';
    const wh = createClient({ baseURL: 'https://wavehouse.example.com' });
    // 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' });

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

    Terminal window
    # Boot ClickHouse + WaveHouse with one compose file
    git clone https://github.com/Wave-RF/WaveHouse.git
    cd WaveHouse
    docker 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 stream
    curl -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.

    WaveHouse is alpha — and built entirely in the open.

    Apache-2.0-licensed, single binary, no SaaS tier, no vendor lock-in. 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 minutes Star on GitHub