ClickHouse Dashboard
Build typed ClickHouse dashboards without a custom data layer
The chart library is usually not the hard part. The hard part is that every panel wants a route, a request helper, a response type, loading state handling, and one more place for the metric definition to drift. hypequery gives the dashboard a cleaner backend path.
Frontend layer
@hypequery/react hooks
Backend layer
@hypequery/serve endpoints
Best for
Multi-chart analytics dashboards
Every chart grows its own fetch path
A dashboard starts with one helper and ends with a patchwork of route handlers, response mappers, and component-specific fetch code. The backend logic becomes harder to reason about than the visual layer.
Panel logic drifts when the metric changes
Rename a field or change an aggregation and you can break half the dashboard if every panel has its own assumptions about the response shape.
Shared filters make duplication worse
Date ranges, tenant scope, and common breakdowns get repeated across panels. That duplication is where dashboards become fragile long before the chart count gets large.
The dashboard shape
Keep query definitions on the server and let the UI consume typed hooks
A dashboard usually wants a small set of named queries, one server-side place to own them, and a client hook layer that inherits those types instead of recreating them in React.
- Generate schema types from ClickHouse with npx @hypequery/cli generate
- Define named dashboard queries with typed inputs and typed outputs
- Keep shared filters and scoping close to the backend definition
- Expose queries over HTTP with @hypequery/serve
- Derive React hooks from the serve API type so the browser stays in sync
Query definitions
Two dashboard queries that live in one server file
This is the part teams often skip. Put the dashboard queries in one file first, then let the client build on top of that instead of inventing panel-by-panel route code.
React dashboard
Panels stay focused on rendering instead of networking glue
Once the hook layer is derived from the API type, the component can just ask for a named query and render the result. That is a better place to spend complexity than hand-maintaining request wrappers around every chart.
This matters more as the dashboard gets bigger. Shared filters, cache invalidation, and panel reuse are all easier when the panels are consuming one typed backend surface.
If your main concern is the hook layer itself, continue to the React page. If the problem is broader application reuse, step back to the analytics page.
Dashboard component
A component that only worries about UI state
The component does not need to know how ClickHouse works. It gets typed data, handles loading state, and renders the panel.
Where teams usually get stuck
The questions this page should answer
What this page replaces
It replaces the usual mix of ad hoc API routes, fetch helpers, and copied response types that accumulate when teams build dashboards panel by panel.
Where the complexity should live
The backend should own metric definitions and response shapes. The frontend should own rendering, interaction, and cache behavior.
When this starts to pay off
You feel the benefit as soon as more than one panel depends on shared filters or reused metrics. That is usually much earlier than teams expect.
What to read next
Use the React page for client-side hook details and the Next.js page if the dashboard lives inside App Router.
Further reading
Go deeper where it actually helps
ClickHouse React
Full guide to typed hooks and hook setup for ClickHouse dashboards.
Open guide
ClickHouse REST API
Expose ClickHouse queries as a typed HTTP API without writing Express routes.
Open guide
ClickHouse Next.js
Combine server components, API routes, and React hooks in a Next.js dashboard.
Open guide
Turn your ClickHouse schema into a type-safe analytics layer
The complete path from schema generation to working dashboard hooks.
Open guide
Next step
Replace one dashboard panel end to end
Take one panel that currently owns its own route and fetch code, move it to a named server query, and let the component consume a typed hook instead. That gives you the real signal quickly.