Guides
Migrating from raw Drizzle
A practical path from hand-written Drizzle query glue to better-drizzle delegates.
The easiest migration is incremental.
1. Keep your existing schema
Do not rewrite tables or relations. better-drizzle reads the Drizzle schema you already have.
2. Wrap the existing Drizzle client once
import { better } from 'better-drizzle';
const db = drizzle(connection, { schema });
export const client = better(db, { schema });3. Move repetitive read paths first
Good first candidates:
- point lookups
- list pages with
include - counts and existence checks
- pagination endpoints
- nested relation filters
These usually deliver the highest reduction in repeated service-layer code.
4. Replace branchy write glue with direct writes
const maybeCreated = await client.users.create({
data: {
email: 'alice@example.com',
name: 'Alice',
},
skipDuplicates: ['email'],
});And for bulk sync paths:
await client.users.upsertMany({
data,
target: ['email'],
update: ['name', 'active'],
});5. Move cross-cutting behavior into plugins or hooks
If you currently repeat logic like:
- timestamps
- soft delete visibility
- audit metadata
- trace IDs
- authorization checks
those are usually better expressed once through plugins or hooks.
Raw Drizzle vs better-drizzle
Keep raw Drizzle when:
- the query is truly custom SQL
- you need a database-specific function or reporting query
- the delegate shape would be more awkward than the SQL
Use better-drizzle when:
- you're rebuilding CRUD and query glue by hand
- you want predictable return shapes
- you want typed relation filters and includes without repeating join code
Migration strategy that works well
- wrap the client
- migrate one service or endpoint at a time
- keep raw SQL where it is the clearest tool
- introduce plugins only after the base delegate API is in use