Databases
Warp supports multiple database providers with Drizzle ORM for type-safe database access.
Supported Providers
Choose the database that fits your needs:
- Supabase - PostgreSQL with built-in auth, storage, and real-time
- Neon - Serverless PostgreSQL with autoscaling
- PlanetScale - MySQL-compatible serverless database
- Turso - Edge SQLite with global replication
- PostgreSQL - Self-hosted or managed PostgreSQL
Drizzle ORM
All databases use Drizzle ORM for:
- Type Safety: Full TypeScript support with autocomplete
- SQL-like Syntax: Familiar query builder
- Migrations: Automatic migration generation
- Relations: Easy foreign key relationships
- Performance: Lightweight with no overhead
Quick Start
1. Choose Your Database
Select a provider during project creation:
npx create-warp@latest my-app
# Select database provider when prompted2. Configure Environment
Add your database URL to .env.local:
DATABASE_URL="postgresql://..."3. Define Schema
Create your schema in db/schema.ts:
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
email: text('email').notNull().unique(),
name: text('name'),
createdAt: timestamp('created_at').defaultNow(),
});4. Generate Migrations
pnpm db:generate5. Run Migrations
pnpm db:migrate6. Use in Your App
import { db } from '@/db';
import { users } from '@/db/schema';
// Insert
await db.insert(users).values({
email: 'user@example.com',
name: 'John Doe',
});
// Query
const allUsers = await db.select().from(users);
// Query with conditions
const user = await db.select()
.from(users)
.where(eq(users.email, 'user@example.com'));Database Scripts
Warp includes helpful scripts in package.json:
# Generate migration from schema changes
pnpm db:generate
# Run migrations
pnpm db:migrate
# Push schema directly (dev only)
pnpm db:push
# Open Drizzle Studio
pnpm db:studioDrizzle Studio
Visual database browser at https://local.drizzle.studio:
pnpm db:studioFeatures:
- Browse tables and data
- Run queries
- Edit records
- View relationships
- Inspect schema
Schema Organization
Organize your schema by feature:
db/
index.ts # Database client
schema.ts # Main schema exports
schema/
users.ts # User tables
products.ts # Product tables
orders.ts # Order tablesExample db/schema.ts:
export * from './schema/users';
export * from './schema/products';
export * from './schema/orders';Common Patterns
Timestamps
Add created/updated timestamps:
export const posts = pgTable('posts', {
id: uuid('id').primaryKey().defaultRandom(),
title: text('title').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
});Relations
Define foreign keys and relations:
import { relations } from 'drizzle-orm';
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
name: text('name').notNull(),
});
export const posts = pgTable('posts', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id').references(() => users.id).notNull(),
title: text('title').notNull(),
});
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
user: one(users, {
fields: [posts.userId],
references: [users.id],
}),
}));Enums
Type-safe enums:
import { pgEnum } from 'drizzle-orm/pg-core';
export const roleEnum = pgEnum('role', ['admin', 'user', 'guest']);
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
role: roleEnum('role').default('user').notNull(),
});Querying
Basic Queries
// Select all
const users = await db.select().from(users);
// Select specific columns
const emails = await db.select({ email: users.email }).from(users);
// Where clause
import { eq, gt, and, or } from 'drizzle-orm';
const activeUsers = await db.select()
.from(users)
.where(eq(users.active, true));
// Multiple conditions
const result = await db.select()
.from(users)
.where(and(
eq(users.active, true),
gt(users.createdAt, new Date('2024-01-01'))
));Joins
const postsWithAuthors = await db.select({
post: posts,
author: users,
})
.from(posts)
.leftJoin(users, eq(posts.userId, users.id));Ordering & Pagination
import { desc, asc } from 'drizzle-orm';
const recentPosts = await db.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(10)
.offset(0);Transactions
Execute multiple operations atomically:
await db.transaction(async (tx) => {
const user = await tx.insert(users).values({
email: 'user@example.com',
}).returning();
await tx.insert(posts).values({
userId: user[0].id,
title: 'First post',
});
});Type Safety
Get full TypeScript types:
import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm';
import { users } from './schema';
// Infer types from schema
type User = InferSelectModel<typeof users>;
type NewUser = InferInsertModel<typeof users>;
// Use in your application
function createUser(data: NewUser): Promise<User> {
// ...
}Best Practices
1. Use Prepared Statements
For repeated queries:
const getUserByEmail = db.select()
.from(users)
.where(eq(users.email, placeholder('email')))
.prepare('get_user_by_email');
const user = await getUserByEmail.execute({ email: 'user@example.com' });2. Index Your Queries
Add indexes for frequently queried columns:
import { index } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
email: text('email').notNull(),
}, (table) => ({
emailIdx: index('email_idx').on(table.email),
}));3. Validate Data
Use Zod for validation before inserting:
import { z } from 'zod';
const userSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
});
const data = userSchema.parse(input);
await db.insert(users).values(data);4. Handle Errors
Wrap database operations in try-catch:
try {
await db.insert(users).values(data);
} catch (error) {
if (error.code === '23505') {
// Unique constraint violation
throw new Error('Email already exists');
}
throw error;
}Migration Strategy
Development
Use db:push for rapid iteration:
pnpm db:pushProduction
Always use migrations:
# Generate migration
pnpm db:generate
# Review migration file in drizzle/
# Apply migration
pnpm db:migrateResources
- Drizzle ORM Docs
- Drizzle Kit - Migration tools
- Database Providers - Provider-specific guides
