Quick Start
Get running in 5 minutes.
From zero to querying your database with auth and permissions in five steps.
The Fastest Way
Scaffold a complete project with one command:
npx @superapp/backend create-app my-appThis creates a monorepo with a configured backend, a Next.js frontend, environment files, and example permissions. Run npm run dev and you're live.
If you prefer to set things up manually, follow the steps below.
Manual Setup
Step 1: Create the Engine Config
Create server.ts in your backend project:
import { createEngine } from '@superapp/backend'
import { betterAuthProvider } from '@superapp/backend/auth/better-auth'
import { postgresProvider } from '@superapp/backend/integrations/postgres'
const auth = betterAuthProvider({
secret: process.env.AUTH_SECRET!,
userTable: {
table: 'main.users',
matchOn: { column: 'id', jwtField: 'id' },
columns: ['id', 'email', 'name'],
},
})
export const engine = createEngine({
superapp_db: './superapp.db',
integrations: [postgresProvider],
connections: {
main: { type: 'postgres', url: process.env.PG_URL! },
},
auth,
masterKey: process.env.SUPERAPP_MASTER_KEY!,
permissions: {
view_own_orders: {
name: 'View own orders',
table: 'main.orders',
operations: { select: true },
columns: ['id', 'amount', 'status', 'customer_id', 'created_at'],
filter: {
organization: {
members: { user_id: { $eq: '$user.id' } },
},
},
},
},
roles: {
viewer: ['view_own_orders'],
},
})Step 2: Start the Server
Add the HTTP adapter below your engine config in the same file, or import the engine into a separate entry point:
import { createHonoMiddleware } from '@superapp/backend/adapters/hono'
import { Hono } from 'hono'
import { serve } from '@hono/node-server'
const app = new Hono()
app.route('/', createHonoMiddleware(engine))
serve({ fetch: app.fetch, port: 3001 }, (info) => {
console.log(`@superapp/backend running on http://localhost:${info.port}`)
})Not using Hono? superapp ships adapters for Next.js, Express, and a generic handler for Cloudflare Workers, Deno, and Bun.
Step 3: Set Up the Client SDK
In your frontend project, create lib/superapp.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,
})
}Generate your SuperAppSchema types by running npx @superapp/backend generate against your running server. This introspects your database and outputs a TypeScript schema file.
Step 4: Add Auth
Wrap your app with AuthProvider and drop in AuthCard for sign-in/sign-up:
// app/layout.tsx
import { AuthProvider } from '@superapp/auth/components'
import { authClient } from '@/lib/superapp'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
export default function RootLayout({ children }: { children: React.ReactNode }) {
const router = useRouter()
return (
<html lang="en">
<body>
<AuthProvider
authClient={authClient}
navigate={router.push}
replace={router.replace}
Link={Link}
onSessionChange={() => router.refresh()}
>
{children}
</AuthProvider>
</body>
</html>
)
}// app/auth/[[...slug]]/page.tsx
import { AuthCard } from '@superapp/auth/components'
export default function AuthPage() {
return (
<div className="flex min-h-screen items-center justify-center">
<AuthCard />
</div>
)
}This gives you /auth/sign-in, /auth/sign-up, and /auth/forgot-password — fully functional, no form code.
Step 5: Query Data
Create a hook to get a typed database client, then query:
// 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],
)
}// app/dashboard/page.tsx
'use client'
import { useEffect, useState } from 'react'
import { useDb } from '@/hooks/use-db'
import { eq, desc } from 'drizzle-orm'
import * as schema from '@/generated/schema'
export default function DashboardPage() {
const db = useDb()
const [orders, setOrders] = useState<any[]>([])
useEffect(() => {
if (!db) return
db.select()
.from(schema.orders)
.where(eq(schema.orders.status, 'active'))
.orderBy(desc(schema.orders.createdAt))
.limit(50)
.then(setOrders)
}, [db])
if (!db) return <p>Please sign in.</p>
return (
<ul>
{orders.map((o) => (
<li key={o.id}>Order #{o.id} - ${o.amount} - {o.status}</li>
))}
</ul>
)
}What You Just Built
Browser Backend Database
| | |
|-- POST /auth/sign-in ------>| |
|<-------- JWT token ---------| |
| | |
|-- POST /data -------------->| |
| (JWT + Drizzle query) | |
| |-- Verify JWT |
| |-- Resolve session ($user) |
| |-- Check permissions |
| |-- Inject WHERE filters |
| | |
| |-- Execute SQL via DuckDB -->|
| |<-------- Results -----------|
| | |
|<------ Typed response ------| |What's Next
- Backend Configuration — Full reference for
createEngineoptions, connections, DuckDB tuning, and security settings. - Client Queries — All query methods:
db.select(),db.insert(),db.update(),db.delete(). - Permissions — Row-level filters, column restrictions, write checks, and preset values.