Choose Your Path - Builder vs Serve
Decide whether to start with the query builder or serve framework
Choose Your Path: Builder vs Serve
hypequery gives you two ways to work with ClickHouse: start with the query builder for simplicity, or use the serve framework when you need APIs and team features.
Start with Builder if...
✅ You're building a dashboard or internal tool
Build type-safe queries directly in your frontend or backend:
const users = await db
.table('users')
.select(['name', 'email'])
.where('active', true)
.execute();Perfect for:
- Internal analytics dashboards
- Admin panels
- Data visualization tools
- Scripted reports
✅ You need type-safe ClickHouse queries
Get full TypeScript autocomplete and compile-time validation:
// Table names, columns, and types are all verified
const result = await db
.table('orders') // ✅ Type-checked
.select(['id', 'total', 'created_at']) // ✅ Validated
.where('status', 'eq', 'completed') // ✅ Type-safe
.execute();Perfect for:
- Replacing raw SQL strings
- Preventing typos in column names
- Catching errors at compile time
- Refactoring with confidence
✅ You're a solo developer or small team
Keep things simple with direct ClickHouse access:
- No HTTP layer to configure
- No authentication setup needed
- No API documentation to maintain
- Just queries, types, and results
✅ You want full control over query execution
Run queries wherever you need them:
- Frontend (browser)
- Backend (Node.js)
- Background jobs
- CLI scripts
- Serverless functions
Add Serve if...
🚀 You need to expose queries as HTTP APIs
Automatically generate endpoints with validation and docs:
const { define, query } = initServe({
context: () => ({ db }),
queries: queries({
weeklyRevenue: query
.describe('Weekly revenue totals')
.input(z.object({ startDate: z.string() }))
.query(({ ctx, input }) =>
ctx.db
.table('orders')
.where('created_at', 'gte', input.startDate)
.sum('total', 'revenue')
.execute()
),
}),
});Perfect for:
- Customer-facing analytics APIs
- Multi-tenant SaaS applications
- Public data endpoints
- Microservices architecture
🚀 Your team needs governance and access controls
Built-in authentication and authorization:
- Role-based access control (RBAC)
- API key authentication
- JWT token validation
- Endpoint-level permissions
- Audit logging
🚀 You're building multi-tenant SaaS applications
Automatic tenant isolation:
- Tenant context injection
- Automatic data filtering
- Prevents cross-tenant data leaks
- Per-tenant query limits
🚀 You want automatic OpenAPI documentation
Generate API docs without writing YAML:
- Auto-generated from queries
- Type-safe request/response schemas
- Interactive API explorer
- SDK generation for frontend
Comparison Table
| Feature | Query Builder | Serve Framework |
|---|---|---|
| Type-safe queries | ✅ | ✅ |
| Direct ClickHouse access | ✅ | ✅ |
| Works in frontend/backend | ✅ | ✅ |
| HTTP API generation | ❌ | ✅ Built-in |
| Authentication (RBAC) | ❌ | ✅ Built-in |
| Multi-tenancy | Manual | ✅ Auto-inject |
| OpenAPI docs | ❌ | ✅ Auto-generated |
| React hooks | ❌ | ✅ Auto-generated |
| Query caching | ✅ Manual | ✅ Built-in strategies |
| Learning curve | Low | Medium |
| Best for | Dashboards, scripts | APIs, multi-tenant apps |
Migration Path
The query builder API is 100% identical in both packages.
// Builder - Direct execution
const result = await db
.table('users')
.where('active', true)
.execute();
// Serve - Same query syntax!
const activeUsers = query
.query(async ({ ctx }) => {
return await ctx.db // Same builder API
.table('users')
.where('active', true)
.execute();
});Migration steps:
- Install
@hypequery/serve - Wrap queries with
defineServe - Add authentication (optional)
- That's it—no query changes needed!
See Migration Guide: Builder → Serve for details.