🛡️ Type-Safe Models
Full TypeScript inference with proxy attribute access, dirty tracking, lifecycle hooks, and mass assignment protection.
Quick Start
Models, migrations, relationships, and revisions — built for Workers.
Type-safe models replace manual interfaces and raw SQL
// Define your own types manually
interface User {
id: string
name: string
email: string
created_at: string
}
// Raw SQL for every operation
const user = await db
.prepare('SELECT * FROM users WHERE id = ?')
.bind(id)
.first<User>()
if (!user) throw new Error('Not found')class User extends BaseModel<UserAttrs> {
static table = 'users'
static timestamps = true
static softDeletes = true
}
// Type-safe, auto-scoped, throws if missing
const user = await User.findOrFail(id)
user.name // fully typed
user.set('email', 'new@mail.com').save()// Define your own types manually
interface User {
id: string
name: string
email: string
created_at: string
}
// Raw SQL for every operation
const user = await db
.prepare('SELECT * FROM users WHERE id = ?')
.bind(id)
.first<User>()
if (!user) throw new Error('Not found')Get started in three steps.
Extend BaseModel with your attributes
class User extends BaseModel<UserAttrs> {
static table = 'users'
static timestamps = true
static softDeletes = true
static relations = {
posts: { type: 'hasMany', model: () => Post }
}
}Schema builder + CLI generators
// Generate migration & model
$ npx d1-eloquent make:model User
$ npx d1-eloquent make:migration create_users
// Apply to D1
$ npx d1-eloquent migrateFully typed, zero raw SQL
const admins = await User.query()
.whereEq('role', 'admin')
.with(['posts'])
.orderBy('name')
.paginate(1, 20)
// { data: User[], total, lastPage, page, perPage }8 generators, migrations, seeders, and schema validation — all from the terminal.
$ npx d1-eloquent make:resource Post --soft-deletes
Created migration: src/database/migrations/2026_03_31_create_posts.ts
Created model: src/app/models/Post.ts
Created factory: src/database/factories/PostFactory.ts
Created seeder: src/database/seeders/PostSeeder.ts
$ npx d1-eloquent make:pivot post_tags
Created migration: src/database/migrations/2026_03_31_post_tags.ts
$ npx d1-eloquent make:types --force
Generating types for 4 model(s)...
Generated: src/types/generated/UserAttrs.ts
Generated: src/types/generated/PostAttrs.ts
Generated: src/types/generated/TagAttrs.ts
Generated: src/types/generated/CommentAttrs.ts
Generated: src/types/generated/index.tsCopy, paste, deploy to Cloudflare Workers.
import { BaseModel, configure } from '@orphnet/d1-eloquent'
interface UserAttrs {
id: string
name: string
email: string
role: string
}
class User extends BaseModel<UserAttrs> {
static table = 'users'
static timestamps = true
}
export default {
async fetch(request: Request, env: Env) {
configure(env)
const admins = await User.query()
.whereEq('role', 'admin')
.orderBy('name')
.get()
return Response.json(admins)
},
}Write TypeScript, get optimized SQL.
const users = await User.query()
.whereEq('role', 'admin')
.whereLike('name', 'A%')
.orderBy('created_at', 'desc')
.limit(10)
.get()SELECT * FROM users
WHERE role = ?
AND name LIKE ?
ORDER BY created_at DESC
LIMIT 10['admin', 'A%']Feature matrix across the D1 ecosystem and beyond.
| Feature | d1-eloquent | Raw D1 API | Drizzle | Laravel |
|---|---|---|---|---|
| Type Safety | ✓ | — | ✓ | — |
| Query Builder | ✓ | — | ✓ | ✓ |
| Relationships | ✓ | — | ~ | ✓ |
| Polymorphic Relations | — | — | — | ✓ |
| Eager Loading | ✓ | — | ✓ | ✓ |
| Soft Deletes | ✓ | — | — | ✓ |
| Revision Tracking | ✓ | — | — | ~ |
| Attribute Casting | ✓ | — | — | ✓ |
| Collection API | ✓ | — | — | ✓ |
| Dirty Tracking | ✓ | — | — | ✓ |
| Lifecycle Hooks | ✓ | — | — | ✓ |
| Schema Migrations | ✓ | — | ✓ | ✓ |
| Seeders & Factories | ✓ | — | — | ✓ |
| Multi-Database | — | — | ✓ | ✓ |
| JSON Column Queries | — | — | ✓ | ✓ |
| Cloudflare D1 | ✓ | ✓ | ✓ | — |
| Edge Runtime | ✓ | ✓ | ✓ | — |
Built for the Cloudflare edge ecosystem
Be the first to know when new releases and features land.