> hypequery

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

FeatureQuery BuilderServe Framework
Type-safe queries
Direct ClickHouse access
Works in frontend/backend
HTTP API generation✅ Built-in
Authentication (RBAC)✅ Built-in
Multi-tenancyManual✅ Auto-inject
OpenAPI docs✅ Auto-generated
React hooks✅ Auto-generated
Query caching✅ Manual✅ Built-in strategies
Learning curveLowMedium
Best forDashboards, scriptsAPIs, 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:

  1. Install @hypequery/serve
  2. Wrap queries with defineServe
  3. Add authentication (optional)
  4. That's it—no query changes needed!

See Migration Guide: Builder → Serve for details.

On this page