ClickHouse Next.js
Build ClickHouse analytics into Next.js without duplicating query logic
This page is about the App Router split: some analytics should run directly in server components, some should be exposed to browser clients, and you do not want those two paths to invent different versions of the same query.
Framework fit
Next.js App Router
Execution model
Local or HTTP
Best for
Dashboards and product analytics
App Router makes it easy to fork the same query
A metric often starts in a server component, then gets copied into a route handler for client-side refresh, then appears again in another page. Next.js makes both paths easy, which is exactly why they drift.
Server and browser consumers need different delivery
The server can call code directly. The browser cannot. The awkward part is keeping those two access modes aligned without rewriting the query for each one.
Route files become accidental analytics files
If the only reusable unit is a loose SQL string, route files and page files start accumulating validation, parsing, and analytics logic that should live elsewhere.
The App Router shape
Keep the query definition outside the route and page files
The cleanest Next.js setup is one shared query definition plus two delivery paths: local execution for server code and a thin App Router handler for browser consumers.
- Generate schema types from your ClickHouse database
- Define reusable analytics queries in TypeScript
- Mount the same API under app/api/* with createFetchHandler
- Run those queries directly in server components and actions
- Add React hooks later without changing the server contract
App Router
One route file that stays thin
The route exists to expose the query, not to become the place where the query is authored.
Server-first usage
Run local in server code, use HTTP only where the browser needs it
The big advantage of Next.js is that not every query needs to go through the network. Use direct execution in server components by default, and reserve HTTP for interactive client-side flows.
That server-first split is what makes this page different from the React page. The React page starts at the client hook layer. This page starts at the question of whether the query should leave the server at all.
If browser hooks are the main concern, continue to the React page. If the concern is general backend reuse outside Next.js, use the Node.js page.
Server component
A server component calling the shared query directly
The component gets the data without a self-HTTP call, but it is still using the same analytics definition the browser path can expose later.
Where teams usually get stuck
The questions this page should answer
What this page is really answering
Not just how to connect ClickHouse to Next.js, but where query logic should live when the framework gives you both server and client execution paths.
Where the duplication usually starts
Usually when a server-rendered dashboard later needs client refresh or filtering and teams copy the query into a route instead of exposing the shared definition cleanly.
Why App Router changes the advice
Because you can often skip HTTP inside the app itself. That is why the local-vs-HTTP split matters more here than on the generic REST page.
Where to go next
Use the React page when the client hook layer is the next problem, not the current one.
Further reading
Go deeper where it actually helps
Building dashboards on ClickHouse with hypequery and Next.js
The practical dashboard-oriented companion to this pillar page.
Open guide
Next.js documentation guide
The implementation path for App Router handlers, local execution, and dev docs.
Open guide
ClickHouse React
Continue into typed hooks and client-side data access patterns.
Open guide
ClickHouse analytics
Step back and evaluate the broader analytics-layer architecture.
Open guide
Next step
Start with the Next.js recipe, then layer in React hooks where they help
Get the App Router setup correct first. After that, decide which analytics belong in server components and which need a browser-facing client layer.