superapp
Client

Overview

Drizzle ORM for the frontend — real Drizzle with an HTTP driver that returns permission-filtered data.

@superapp/db gives your frontend real Drizzle ORM connected to any database through the superapp backend. Same API you already know — the data you get back is already filtered, restricted, and validated by the backend's permission engine.

How It Works

The client uses a Drizzle HTTP driver plugin that sends queries to the superapp backend. The server validates your JWT, applies row-level permissions, and executes against your database. The data returned to the client has already been filtered and restricted by the permission engine — the client consumes Drizzle ORM, but with all data scoped to the user's configured permissions.

  Your Frontend                superapp Backend                  Database
  ─────────────                ────────────────                  ────────
  db.select(...)  ── JSON ──▶  Verify JWT
                               Who is this user?


                               Apply permissions
                               • Add WHERE user_id = ?
                               • Restrict visible columns
                               • Validate write operations


                               Build & run SQL  ─── query ────▶  Postgres
                                                                 MySQL
                               Return filtered  ◀── results ──  SQLite
                                  results                        CSV

  Receive scoped  ◀── JSON ──       │
  data only

You write normal Drizzle queries. The backend ensures each user only sees their own data.

Quick Example

import { drizzle } from '@superapp/db'
import { eq, desc } from 'drizzle-orm'
import * as schema from './generated/schema'

// The token ties this Drizzle instance to a specific user.
// Every query through this `db` will only return that user's data.
const db = drizzle({
  connection: 'http://localhost:3001',
  token: session.token,  // ← JWT identifies the logged-in user
  schema,
})

// This looks like a normal Drizzle query — no user_id filter needed.
// The backend reads the JWT, resolves the user, and automatically
// scopes results so this user can only see their own orders.
const orders = await db.select()
  .from(schema.orders)
  .where(eq(schema.orders.status, 'active'))
  .orderBy(desc(schema.orders.createdAt))
  .limit(10)

// If Alice is logged in:  returns only Alice's active orders
// If Bob is logged in:    returns only Bob's active orders
// Same code, different data — enforced by the backend, not the client

Available Methods

MethodDescription
db.select()Select rows with filtering, sorting, joins, and pagination
db.query.*.findMany()Relational queries with eager loading
db.query.*.findFirst()Find a single record with relations
db.insert()Insert one or more rows
db.update()Update rows matching a condition
db.delete()Delete rows matching a condition
db.select({ count: count() })Count rows
db.select({ total: sum() })Aggregations (sum, avg, min, max)

Imports Summary

ImportPathDescription
drizzle@superapp/dbCreate a Drizzle client with HTTP driver
eq, gt, desc, ...drizzle-ormStandard Drizzle filter and sort operators
schema./generated/schemaAuto-generated Drizzle schema from your database
createAuth@superapp/authAuth client for session management
useSession@superapp/authReact hook for current session
AuthProvider@superapp/auth/componentsRoot layout wrapper for auth context
AuthCard@superapp/auth/componentsPre-built sign-in/sign-up/forgot-password UI
UserButton@superapp/auth/componentsNavbar dropdown with avatar and sign out

What's Next

On this page