Skip to content
Beta — Truss is in public beta. Documentation is actively updated but may not reflect the latest changes. Report issues on GitHub.

Drizzle ORM

Drizzle ORM is a lightweight, type-safe TypeScript ORM that works directly with your Truss PostgreSQL database. This guide covers connection setup, schema definition, migrations, and realtime integration.

Install Drizzle and the PostgreSQL driver:

Terminal window
npm install drizzle-orm postgres
npm install -D drizzle-kit

Grab your connection string from the Truss dashboard under Database > Connection. Set it as an environment variable:

.env
DATABASE_URL=postgresql://postgres:your-password@your-truss-host:5432/truss

Create a database client:

src/db.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle(client);

Drizzle schemas are plain TypeScript files that map to PostgreSQL tables:

src/schema.ts
import { pgTable, serial, text, timestamp, boolean } from 'drizzle-orm/pg-core';
export const todos = pgTable('todos', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
completed: boolean('completed').default(false),
createdAt: timestamp('created_at').defaultNow(),
});

Configure Drizzle Kit:

drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});

Generate and apply migrations:

Terminal window
# Generate SQL migration files from schema changes
npx drizzle-kit generate
# Apply pending migrations to the database
npx drizzle-kit migrate

Drizzle Kit creates a drizzle/ directory containing .sql migration files and a meta/ directory for tracking state.

You can also run Drizzle-generated SQL migrations through the Truss Migration API. Place your .sql files in the Truss migrations directory (apps/api/db/migrations/) and use the idempotent runner:

Terminal window
# Check migration status (Truss auto-detects Drizzle's tracking table)
curl http://localhost:8787/api/migrations/idempotent/status
# Run pending migrations
curl -X POST http://localhost:8787/api/migrations/idempotent/run

For rapid prototyping, push schema changes directly without generating migration files:

Terminal window
npx drizzle-kit push

This applies changes directly to the database. Not recommended for production.


Truss automatically detects the drizzle.__drizzle_migrations tracking table. Once you’ve run at least one Drizzle migration, the Truss dashboard Database > Migrations panel will:

  • Show your detected framework as “Drizzle ORM”
  • List all applied and pending migrations with status badges
  • Let you preview, run, or mark migrations as applied from the UI
  • Detect schema conflicts before running

No configuration is needed. Truss scans for the tracking table on each status check.


Use Drizzle’s type-safe query builder:

import { db } from './db';
import { todos } from './schema';
import { eq } from 'drizzle-orm';
// Insert a row
const [newTodo] = await db.insert(todos).values({
title: 'Ship the feature',
}).returning();
// Select all incomplete todos
const pending = await db.select()
.from(todos)
.where(eq(todos.completed, false));
// Update a row
await db.update(todos)
.set({ completed: true })
.where(eq(todos.id, newTodo.id));
// Delete a row
await db.delete(todos).where(eq(todos.id, newTodo.id));

Truss provides realtime subscriptions via PostgreSQL LISTEN/NOTIFY. You can combine Drizzle for writes and Truss realtime for live updates.

First, subscribe to a table via the Truss API or dashboard:

Terminal window
curl -X POST http://localhost:8787/api/realtime/subscribe \
-H "Content-Type: application/json" \
-d '{"schema": "public", "table": "todos"}'

Then connect a WebSocket client to receive events when Drizzle writes to the table:

const ws = new WebSocket('ws://your-truss-host:8787/realtime');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.table === 'todos') {
console.log(`${data.operation}: ${JSON.stringify(data.row)}`);
}
};
// Now, any Drizzle insert/update/delete on 'todos' triggers a realtime event
await db.insert(todos).values({ title: 'New task' });
// WebSocket receives: { operation: "INSERT", table: "todos", row: { ... } }

This pattern works well for React apps: use Drizzle on the server for mutations, and a WebSocket hook on the client for live updates.


  • The Truss SQL workbench is read-only (SELECT, WITH, EXPLAIN). DDL and DML run through Drizzle CLI or the Migration API.
  • Drizzle connects directly to PostgreSQL. The Truss API is not in the query path, so there is no added latency.
  • For database branching, point DATABASE_URL at the branch database. See Branching & Backups.
  • Truss supports pgvector. You can define vector columns in Drizzle using customType and query them through the Truss Vectors panel.