Agent SkillsAgent Skills
jezweb

d1-drizzle-schema

@jezweb/d1-drizzle-schema
jezweb
673
52 forks
Updated 4/1/2026
View on GitHub

Generate Drizzle ORM schemas for Cloudflare D1 databases with correct D1-specific patterns. Produces schema files, migration commands, type exports, and DATABASE_SCHEMA.md documentation. Handles D1 quirks: foreign keys always enforced, no native BOOLEAN/DATETIME types, 100 bound parameter limit, JSON stored as TEXT. Use when creating a new database, adding tables, or scaffolding a D1 data layer.

Installation

$npx agent-skills-cli install @jezweb/d1-drizzle-schema
Claude Code
Cursor
Copilot
Codex
Antigravity

Details

Pathskills/d1-drizzle-schema/SKILL.md
Branchmain
Scoped Name@jezweb/d1-drizzle-schema

Usage

After installing, this skill will be available to your AI coding assistant.

Verify installation:

npx agent-skills-cli list

Skill Instructions


name: d1-drizzle-schema description: "Generate Drizzle ORM schemas for Cloudflare D1 databases with correct D1-specific patterns. Produces schema files, migration commands, type exports, and DATABASE_SCHEMA.md documentation. Handles D1 quirks: foreign keys always enforced, no native BOOLEAN/DATETIME types, 100 bound parameter limit, JSON stored as TEXT. Use when creating a new database, adding tables, or scaffolding a D1 data layer." compatibility: claude-code-only

D1 Drizzle Schema

Generate correct Drizzle ORM schemas for Cloudflare D1. D1 is SQLite-based but has important differences that cause subtle bugs if you use standard SQLite patterns. This skill produces schemas that work correctly with D1's constraints.

Critical D1 Differences

FeatureStandard SQLiteD1
Foreign keysOFF by defaultAlways ON (cannot disable)
Boolean typeNoNo β€” use integer({ mode: 'boolean' })
Datetime typeNoNo β€” use integer({ mode: 'timestamp' })
Max bound params~999100 (affects bulk inserts)
JSON supportExtensionAlways available (json_extract, ->, ->>)
ConcurrencyMulti-writerSingle-threaded (one query at a time)

Workflow

Step 1: Describe the Data Model

Gather requirements: what tables, what relationships, what needs indexing. If working from an existing description, infer the schema directly.

Step 2: Generate Drizzle Schema

Create schema files using D1-correct column patterns:

import { sqliteTable, text, integer, real, index, uniqueIndex } from 'drizzle-orm/sqlite-core'

export const users = sqliteTable('users', {
  // UUID primary key (preferred for D1)
  id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),

  // Text fields
  name: text('name').notNull(),
  email: text('email').notNull(),

  // Enum (stored as TEXT, validated at schema level)
  role: text('role', { enum: ['admin', 'editor', 'viewer'] }).notNull().default('viewer'),

  // Boolean (D1 has no BOOL β€” stored as INTEGER 0/1)
  emailVerified: integer('email_verified', { mode: 'boolean' }).notNull().default(false),

  // Timestamp (D1 has no DATETIME β€” stored as unix seconds)
  createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
  updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),

  // Typed JSON (stored as TEXT, Drizzle auto-serialises)
  preferences: text('preferences', { mode: 'json' }).$type<UserPreferences>(),

  // Foreign key (always enforced in D1)
  organisationId: text('organisation_id').references(() => organisations.id, { onDelete: 'cascade' }),
}, (table) => ({
  emailIdx: uniqueIndex('users_email_idx').on(table.email),
  orgIdx: index('users_org_idx').on(table.organisationId),
}))

See references/column-patterns.md for the full type reference.

Step 3: Add Relations

Drizzle relations are query builder helpers (separate from FK constraints):

import { relations } from 'drizzle-orm'

export const usersRelations = relations(users, ({ one, many }) => ({
  organisation: one(organisations, {
    fields: [users.organisationId],
    references: [organisations.id],
  }),
  posts: many(posts),
}))

Step 4: Export Types

export type User = typeof users.$inferSelect
export type NewUser = typeof users.$inferInsert

Step 5: Set Up Drizzle Config

Copy assets/drizzle-config-template.ts to drizzle.config.ts and update the schema path.

Step 6: Add Migration Scripts

Add to package.json:

{
  "db:generate": "drizzle-kit generate",
  "db:migrate:local": "wrangler d1 migrations apply DB --local",
  "db:migrate:remote": "wrangler d1 migrations apply DB --remote"
}

Always run on BOTH local AND remote before testing.

Step 7: Generate DATABASE_SCHEMA.md

Document the schema for future sessions:

  • Tables with columns, types, and constraints
  • Relationships and foreign keys
  • Indexes and their purpose
  • Migration workflow

Bulk Insert Pattern

D1 limits bound parameters to 100. Calculate batch size:

const BATCH_SIZE = Math.floor(100 / COLUMNS_PER_ROW)
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
  await db.insert(table).values(rows.slice(i, i + BATCH_SIZE))
}

D1 Runtime Usage

import { drizzle } from 'drizzle-orm/d1'
import * as schema from './schema'

// In Worker fetch handler:
const db = drizzle(env.DB, { schema })

// Query patterns
const all = await db.select().from(schema.users).all()           // Array<User>
const one = await db.select().from(schema.users).where(eq(schema.users.id, id)).get()  // User | undefined
const count = await db.select({ count: sql`count(*)` }).from(schema.users).get()

Reference Files

WhenRead
D1 vs SQLite, JSON queries, limitsreferences/d1-specifics.md
Column type patterns for Drizzle + D1references/column-patterns.md

Assets

FilePurpose
assets/drizzle-config-template.tsStarter drizzle.config.ts for D1
assets/schema-template.tsExample schema with all common D1 patterns

More by jezweb

View all
electron-base
673

Build secure desktop applications with Electron 33, Vite, React, and TypeScript. Covers type-safe IPC via contextBridge, OAuth with custom protocol handlers, native module compatibility (better-sqlite3, electron-store), and electron-builder packaging. Use when building cross-platform desktop apps, implementing OAuth flows in Electron, handling main/renderer process communication, or packaging with code signing. Prevents: NODE_MODULE_VERSION mismatch, hardcoded encryption keys, context isolation bypasses, sandbox conflicts with native modules.

dependency-audit
673

Comprehensive dependency health auditing for JavaScript/TypeScript projects. Run npm audit, detect outdated packages, check for security advisories, and verify license compliance. Prioritises vulnerabilities by severity and provides actionable fix recommendations. Use when: auditing project dependencies, checking for vulnerabilities, updating packages, preparing for release, or investigating "npm audit" warnings. Keywords: audit, vulnerabilities, outdated, security, npm audit, pnpm audit, CVE, GHSA, license.

skill-development
673

Tools for creating, auditing, and maintaining Claude Code skills. Includes /create-skill for scaffolding, /review-skill for quality checks, and /audit commands for bulk verification. Use when: building new skills, maintaining skill quality, or forking claude-skills repo.

shadcn-ui
673

Install and configure shadcn/ui components for React projects. Guides component selection, installation order, dependency management, customisation with semantic tokens, and common UI recipes (forms, data tables, navigation, modals). Use after tailwind-theme-builder has set up the theme infrastructure, when adding components, building forms, creating data tables, or setting up navigation.