superapp
Client

Setup

Configure the Drizzle ORM client with your superapp backend connection and generated schema.

The drizzle() function creates a Drizzle ORM instance configured with an HTTP driver that connects to your superapp backend.

import { drizzle } from '@superapp/db'
import * as schema from './generated/schema'

// Each user gets their own Drizzle instance tied to their JWT.
// All queries through this `db` are automatically scoped to this user's data.
const db = drizzle({
  connection: 'http://localhost:3001',
  token: session.token,  // ← identifies who this user is
  schema,
})

Options

OptionTypeRequiredDescription
connectionstringYesYour superapp backend URL
tokenstringYesA valid JWT obtained from the auth client
schemaobjectYesYour generated Drizzle schema object

Schema Import

The schema is auto-generated from your database by the CLI. It contains standard Drizzle table definitions:

import * as schema from './generated/schema'

// schema.orders → pgTable('orders', { ... })
// schema.customers → pgTable('customers', { ... })
// schema.ordersRelations → relations(orders, ({ one }) => ({ ... }))

See Type Generation for how to generate the schema.

Create a shared setup file and a React hook for easy access across your app.

lib/db.ts

import { drizzle } from '@superapp/db'
import { createAuth } from '@superapp/auth'
import * as schema from '../generated/schema'

const SUPERAPP_URL = process.env.NEXT_PUBLIC_SUPERAPP_URL!

export const authClient = createAuth(SUPERAPP_URL)

export function createDb(token: string) {
  return drizzle({
    connection: SUPERAPP_URL,
    token,
    schema,
  })
}

hooks/use-db.ts

import { useMemo } from 'react'
import { useSession } from '@superapp/auth'
import { createDb } from '@/lib/db'

export function useDb() {
  const { data: session } = useSession()
  return useMemo(
    () => (session?.token ? createDb(session.token) : null),
    [session?.token]
  )
}

Usage in a component:

import { useDb } from '@/hooks/use-db'
import { eq, desc } from 'drizzle-orm'
import * as schema from '@/generated/schema'

export function OrdersList() {
  const db = useDb()

  async function loadOrders() {
    if (!db) return
    // No user_id filter needed — the backend scopes results automatically.
    // Each user only sees their own orders.
    const orders = await db.select()
      .from(schema.orders)
      .where(eq(schema.orders.status, 'active'))
      .orderBy(desc(schema.orders.createdAt))
      .limit(50)
  }
}

How It Works

When you call a Drizzle query method, the HTTP driver:

  1. Serializes the query to a structured format.
  2. POSTs it to the backend with the JWT in the Authorization header.
  3. The backend validates the token, applies row-level permissions, and executes the query.
  4. Returns the typed result.

The query syntax is identical to standard Drizzle ORM — the only difference is the transport layer.

On this page