Skip to main content
The Drizzle adapter enables Arraf Auth to work with PostgreSQL databases using Drizzle ORM, providing type-safe database operations with excellent performance.

Installation

npm install @arraf-auth/adapter-drizzle drizzle-orm postgres
npm install -D drizzle-kit

Setup

1. Define Database Schema

You can either use the pre-built schema from the adapter or define your own schema:
import { users, sessions, accounts, verifications } from "@arraf-auth/adapter-drizzle"

// The adapter exports ready-to-use table definitions
export { users, sessions, accounts, verifications }
Important Schema Requirements:
  • Use text type for IDs with $defaultFn for auto-generation
  • email and phone must be nullable and unique
  • Foreign keys should use onDelete: "cascade" for automatic cleanup
  • The verification_type enum uses underscores instead of hyphens
  • Add indexes on frequently queried fields (userId, token)

2. Create Drizzle Config

Create a drizzle.config.ts file in your project root:
drizzle.config.ts
import type { Config } from "drizzle-kit"

export default {
  schema: "./lib/db/schema.ts",
  out: "./drizzle",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
} satisfies Config

3. Generate and Run Migrations

Generate migration files and apply them to your database:
# Generate migration
npx drizzle-kit generate

# Apply migrations
npx drizzle-kit push

4. Create Database Connection

Set up your Drizzle database connection:
lib/db/index.ts
import { drizzle } from "drizzle-orm/postgres-js"
import postgres from "postgres"
import * as schema from "./schema"

const client = postgres(process.env.DATABASE_URL!)
export const db = drizzle(client, { schema })

5. Configure Arraf Auth

Use the Drizzle adapter in your Arraf Auth configuration:
lib/auth.ts
import { createAuth } from "@arraf-auth/core"
import { drizzleAdapter } from "@arraf-auth/adapter-drizzle"
import { db } from "./db"

export const auth = createAuth({
  secret: process.env.AUTH_SECRET!,
  database: drizzleAdapter(db),
  session: {
    strategy: "database",
    expiresIn: "7d",
  },
})

Usage with Next.js

import { auth } from "@/lib/auth"

export const { GET, POST } = auth.handler()

API Reference

drizzleAdapter

Creates a database adapter for Drizzle ORM.
db
PostgresJsDatabase
required
An instance of the Drizzle database client configured with postgres-js.
adapter
DatabaseAdapter
A database adapter that implements all required methods for Arraf Auth.
Example:
import { drizzle } from "drizzle-orm/postgres-js"
import postgres from "postgres"
import { drizzleAdapter } from "@arraf-auth/adapter-drizzle"

const client = postgres(process.env.DATABASE_URL!)
const db = drizzle(client)
const adapter = drizzleAdapter(db)

Exported Schema Types

The adapter exports TypeScript types for all table records:
import type {
  UserRecord,
  SessionRecord,
  AccountRecord,
  VerificationRecord,
} from "@arraf-auth/adapter-drizzle"

// Use in your application
function processUser(user: UserRecord) {
  // Type-safe user handling
}

Schema Field Mapping

The adapter handles automatic conversion between Drizzle’s enum format and Arraf Auth’s type format:
Arraf Auth TypeDrizzle Enum
phone-otpphone_otp
email-otpemail_otp
email-verificationemail_verification
password-resetpassword_reset
phone-changephone_change
The adapter automatically converts between hyphenated and underscored formats using internal helper functions.

Advanced Usage

Custom ID Generation

The default schema uses a simple ID generation function. For production, consider using a more robust solution:
import { customAlphabet } from "nanoid"

const createId = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz", 21)

export const users = pgTable("users", {
  id: text("id").primaryKey().$defaultFn(createId),
  // ... other fields
})

Connection Pooling

For better performance in production, configure connection pooling:
import postgres from "postgres"

const client = postgres(process.env.DATABASE_URL!, {
  max: 10, // Maximum pool size
  idle_timeout: 20,
  connect_timeout: 10,
})

Using with Neon or Supabase

import { neon } from "@neondatabase/serverless"
import { drizzle } from "drizzle-orm/neon-http"

const sql = neon(process.env.DATABASE_URL!)
const db = drizzle(sql)

Querying User Data

You can use Drizzle’s query API alongside the adapter:
import { eq } from "drizzle-orm"
import { db } from "@/lib/db"
import { users, sessions } from "@arraf-auth/adapter-drizzle"

// Find user with sessions
const userWithSessions = await db.query.users.findFirst({
  where: eq(users.id, userId),
  with: {
    sessions: true,
  },
})

// Count active sessions
const activeSessions = await db
  .select()
  .from(sessions)
  .where(eq(sessions.userId, userId))

Migration from Prisma

If you’re migrating from Prisma to Drizzle:
  1. Generate Drizzle schema from your Prisma database:
    npx drizzle-kit introspect
    
  2. Compare the generated schema with the required Arraf Auth schema
  3. Update your auth configuration to use the Drizzle adapter

Troubleshooting

Error: relation does not exist

Make sure you’ve run the migrations:
npx drizzle-kit push

Error: enum type does not exist

Ensure the verification_type enum is created in your database. Run:
npx drizzle-kit generate
npx drizzle-kit push

Type errors with database client

Make sure you’re using the correct Drizzle database type:
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js"

Next Steps

Build docs developers (and LLMs) love