Skip to main content
skill CX Codex

d1-drizzle-schema — Claude Code skill: what it does, how to install

Generates Drizzle ORM schemas tailored for Cloudflare D1 quirks. Helps scaffold tables, write migration scripts, and document database structures.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add jezweb/claude-skills --skill d1-drizzle-schema -a claude-code
Open on GitHub

What d1-drizzle-schema does

Standard SQLite patterns cause subtle bugs when applied directly to Cloudflare D1. D1 enforces foreign keys at all times and does not offer native boolean or datetime types. This skill configures columns using integer({ mode: 'boolean' }) and integer({ mode: 'timestamp' }), stores JSON fields as text, and maps relations.

The generator outputs TypeScript schemas, inferred $inferSelect and $inferInsert types, a starter drizzle.config.ts, and DATABASE_SCHEMA.md. It also writes migration scripts for wrangler d1 migrations apply targeting both local and remote environments.

Cloudflare caps bound parameters at 100 per statement. A regular bulk insert crashes immediately when row count multiplied by column count exceeds that limit. The skill writes chunked insert loops based on Math.floor(100 / COLUMNS_PER_ROW) to keep payloads safe.

What it helps with

  • generate Drizzle ORM schemas aligned with Cloudflare D1 constraints
  • store boolean flags and timestamps as integers correctly
  • batch bulk inserts around the 100 bound parameter ceiling
  • add local and remote wrangler migration commands to package.json
  • document tables and relationships in DATABASE_SCHEMA.md

Example prompts for the agent

  • Generate a Drizzle schema for users and organisations in Cloudflare D1
  • Set up D1 migration scripts and drizzle.config.ts for this project
  • Scaffold a batch insert helper for D1 respecting parameter limits

How to install d1-drizzle-schema

1Skills CLI (Vercel)

npx skills add jezweb/claude-skills --skill d1-drizzle-schema -a claude-code

2Manually: put the files in place

~/.claude/skills/d1-drizzle-schema/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/d1-drizzle-schema/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about d1-drizzle-schema

How to install d1-drizzle-schema in Claude Code?

Run npx skills add jezweb/claude-skills --skill d1-drizzle-schema -a claude-code in your terminal. The skill file is placed in ~/.claude/skills/d1-drizzle-schema/SKILL.md.

What does d1-drizzle-schema do?

It scaffolds Drizzle ORM schemas specifically configured for Cloudflare D1. The skill covers column modes for timestamps and booleans, query relations, type exports, and documentation.

How does the skill handle bulk inserts in Cloudflare D1?

D1 caps bound query parameters at 100. The skill calculates batch sizes using Math.floor(100 / COLUMNS_PER_ROW) and chunks insert operations across separate queries.

Source text

SKILL.md · MIT
---
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

| Feature | Standard SQLite | D1 |
|---------|-----------------|-----|
| Foreign keys | OFF by default | **Always ON** (cannot disable) |
| Boolean type | No | No — use `integer({ mode: 'boolean' })` |
| Datetime type | No | No — use `integer({ mode: 'timestamp' })` |
| Max bound params | ~999 | **100** (affects bulk inserts) |
| JSON support | Extension | **Always available** (json_extract, ->, ->>) |
| Concurrency | Multi-writer | **Single-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:

```typescript
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](references/column-patterns.md) for the full type reference.

### Step 3: Add Relations

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

```typescript
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

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

### Step 5: Set Up Drizzle Config

Copy [assets/drizzle-config-template.ts](assets/drizzle-config-template.ts) to `drizzle.config.ts` and update the schema path.

### Step 6: Add Migration Scripts

Add to `package.json`:
```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:

```typescript
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

```typescript
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

| When | Read |
|------|------|
| D1 vs SQLite, JSON queries, limits | [references/d1-specifics.md](references/d1-specifics.md) |
| Column type patterns for Drizzle + D1 | [references/column-patterns.md](references/column-patterns.md) |

## Assets

| File | Purpose |
|------|---------|
| [assets/drizzle-config-template.ts](assets/drizzle-config-template.ts) | Starter drizzle.config.ts for D1 |
| [assets/schema-template.ts](assets/schema-template.ts) | Example schema with all common D1 patterns |

© jezweb · MIT · jezweb/claude-skills

Similar skills

All skills for Data and databases →

From the same set60

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor