Drizzle

Drizzle ORM

Drizzle ORM is a TypeScript-first ORM with a SQL-like query API and schema migration tooling.

ℹ️

Drizzle support is currently under active development, already offering full query API support. However, certain advanced features are not yet available:

  • Inter-table dependencies (e.g., foreign keys in schema definitions)
  • Schema migrations / introspection (drizzle-kit pull)

The official getting-started tutorial works out of the box with CedarDB:

Setting up CedarDB

Start CedarDB in server mode and create a user and database:

./cedardb --createdb mydb
psql -h /tmp -U postgres
create user myuser with password 'mypassword' superuser;
create database mydb;

Then enable TCP connections:

./cedardb mydb --address=::

For more details, see the install guide.

Installing

Install Drizzle ORM, the pg driver, and the Drizzle Kit CLI:

npm install drizzle-orm pg dotenv
npm install --save-dev drizzle-kit tsx @types/pg

Connecting

Create a .env file with your CedarDB connection string:

.env
DATABASE_URL=postgresql://myuser:mypassword@localhost:5432/mydb

Initialize the Drizzle client in src/index.ts:

src/index.ts
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/node-postgres';

const db = drizzle(process.env.DATABASE_URL!);

Defining a Schema

Create a schema file at src/db/schema.ts:

src/db/schema.ts
import { integer, pgTable, varchar } from "drizzle-orm/pg-core";

export const usersTable = pgTable("users", {
  id: integer().primaryKey().generatedAlwaysAsIdentity(),
  name: varchar({ length: 255 }).notNull(),
  age: integer().notNull(),
  email: varchar({ length: 255 }).notNull().unique(),
});

Create a drizzle.config.ts in your project root:

drizzle.config.ts
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

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

Applying the Schema

Push the schema to CedarDB using Drizzle Kit:

npx drizzle-kit push

This creates the users table directly in CedarDB without generating migration files.

Querying

The full range of Drizzle’s query API works with CedarDB:

import 'dotenv/config';
import { drizzle } from 'drizzle-orm/node-postgres';
import { and, avg, count, desc, eq, gt, like } from 'drizzle-orm';
import { usersTable } from './db/schema';

const db = drizzle(process.env.DATABASE_URL!);

// Insert a single row
await db.insert(usersTable).values({ name: 'Alice', age: 28, email: 'alice@example.com' });

// Batch insert with RETURNING
const inserted = await db
  .insert(usersTable)
  .values([
    { name: 'Bob',   age: 35, email: 'bob@example.com'   },
    { name: 'Carol', age: 22, email: 'carol@example.com' },
  ])
  .returning({ id: usersTable.id, name: usersTable.name });

// Filtered select
const result = await db
  .select()
  .from(usersTable)
  .where(and(gt(usersTable.age, 30), like(usersTable.name, '%o%')));

// Ordered select with LIMIT
const top2 = await db
  .select({ name: usersTable.name, age: usersTable.age })
  .from(usersTable)
  .orderBy(desc(usersTable.age))
  .limit(2);

// Aggregates
const [{ userCount }] = await db.select({ userCount: count() }).from(usersTable);
const [{ avgAge }]    = await db.select({ avgAge: avg(usersTable.age) }).from(usersTable);

// Update
await db.update(usersTable).set({ age: 36 }).where(eq(usersTable.email, 'bob@example.com'));

// Upsert
await db
  .insert(usersTable)
  .values({ name: 'Bob', age: 99, email: 'bob@example.com' })
  .onConflictDoUpdate({ target: usersTable.email, set: { age: 99 } });

// Transaction
await db.transaction(async (tx) => {
  const [user] = await tx
    .insert(usersTable)
    .values({ name: 'Dave', age: 40, email: 'dave@example.com' })
    .returning({ id: usersTable.id });
  await tx.update(usersTable).set({ age: 41 }).where(eq(usersTable.id, user.id));
});

// Delete
await db.delete(usersTable).where(eq(usersTable.email, 'alice@example.com'));

Known Limitations

CedarDB’s Drizzle support is actively being developed. The following are known limitations:

Foreign keys and inter-table dependencies are not yet supported. Schemas with references() between tables will not work correctly.

Schema introspection (drizzle-kit pull) is not supported. Drizzle cannot read an existing CedarDB schema and generate TypeScript definitions from it.

Raw DDL via db.execute is available as a workaround for schema changes that Drizzle does not expose natively:

import { sql } from 'drizzle-orm';

await db.execute(sql`ALTER TABLE users ADD COLUMN phone text`);
await db.execute(sql`ALTER TABLE users DROP COLUMN phone`);