
D1 Drizzle Schema
Scaffold a typed Drizzle schema and drizzle-kit config for Cloudflare D1 when you are wiring SQLite tables, relations, and migrations on Workers.
Overview
d1-drizzle-schema is an agent skill for the Build phase that supplies a Drizzle ORM and drizzle-kit template for Cloudflare D1 SQLite schemas and migration layout.
Install
npx skills add https://github.com/jezweb/claude-skills --skill d1-drizzle-schemaWhat is this skill?
- drizzle-kit defineConfig with dialect sqlite, driver d1-http, and CLOUDFLARE account/database/token env vars
- Reference sqliteTable patterns: UUID text PK, text enums, boolean as integer, timestamp integers, JSON text columns
- users table example with unique email index, relations imports, and strict/verbose kit flags
- Demonstrates common D1 column patterns in one copy-pasteable schema module
- Schema template demonstrates users table with unique email index and typed JSON preferences column
Adoption & trust: 1.2k installs on skills.sh; 841 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are on Workers with D1 but lack a typed Drizzle schema, kit config, and consistent column patterns for SQLite on the edge.
Who is it for?
Indie SaaS or APIs on Cloudflare D1 who already use TypeScript and want Drizzle conventions without reverse-engineering D1-specific types.
Skip if: Projects on Postgres/MySQL only, raw D1 SQL without ORM, or teams that need a full auth or multi-tenant data model out of the box.
When should I use this skill?
User is authoring or extending Cloudflare D1 persistence with Drizzle ORM, drizzle-kit config, or SQLite column patterns on Workers.
What do I get? / Deliverables
You get a ready drizzle-kit config plus an exemplar schema file with indexes, enums, JSON, and timestamps you can extend before generating migrations.
- drizzle.config exporting defineConfig for sqlite dialect and d1-http driver
- src/server/db/schema.ts with exemplar tables, indexes, and relation imports
Recommended Skills
Journey fit
Database schema and migration layout belong in Build once the product shape is set and you are persisting data on the edge. Backend subphase is where ORM tables, indexes, foreign keys, and D1-http driver credentials are defined—not during ideation or launch copy.
How it compares
A schema starter template—not a managed migration service or generic SQL generator for non-SQLite databases.
Common Questions / FAQ
Who is d1-drizzle-schema for?
Solo and indie builders shipping on Cloudflare Workers with D1 who want Drizzle ORM tables, enums, and drizzle-kit wiring in one place.
When should I use d1-drizzle-schema?
During Build backend work when you are creating src/server/db/schema.ts, configuring drizzle-kit for d1-http, or standardizing UUID, boolean, and timestamp columns on D1.
Is d1-drizzle-schema safe to install?
Review the Security Audits panel on this Prism page for install risk and file integrity; the skill exposes Cloudflare credential placeholders you must keep in env secrets, not committed keys.
SKILL.md
READMESKILL.md - D1 Drizzle Schema
import { defineConfig } from 'drizzle-kit' export default defineConfig({ schema: './src/server/db/schema.ts', out: './drizzle', dialect: 'sqlite', driver: 'd1-http', dbCredentials: { accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, databaseId: process.env.CLOUDFLARE_D1_DATABASE_ID!, token: process.env.CLOUDFLARE_API_TOKEN!, }, verbose: true, strict: true, }) /** * D1 Drizzle Schema Template * * Demonstrates all common D1 column patterns: * - UUID primary key, text with enums, boolean as integer, * timestamp as integer, typed JSON, foreign keys, indexes */ import { sqliteTable, text, integer, real, index, uniqueIndex } from 'drizzle-orm/sqlite-core' import { relations } from 'drizzle-orm' // --- Users --- export const users = sqliteTable('users', { id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()), name: text('name').notNull(), email: text('email').notNull(), role: text('role', { enum: ['admin', 'editor', 'viewer'] }).notNull().default('viewer'), emailVerified: integer('email_verified', { mode: 'boolean' }).notNull().default(false), preferences: text('preferences', { mode: 'json' }).$type<Record<string, unknown>>(), createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()), updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()), }, (table) => ({ emailIdx: uniqueIndex('users_email_idx').on(table.email), })) export const usersRelations = relations(users, ({ many }) => ({ posts: many(posts), })) // --- Posts --- export const posts = sqliteTable('posts', { id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()), title: text('title').notNull(), content: text('content'), status: text('status', { enum: ['draft', 'published', 'archived'] }).notNull().default('draft'), authorId: text('author_id').notNull().references(() => users.id, { onDelete: 'cascade' }), metadata: text('metadata', { mode: 'json' }).$type<Record<string, unknown>>(), publishedAt: integer('published_at', { mode: 'timestamp' }), createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()), }, (table) => ({ authorIdx: index('posts_author_idx').on(table.authorId), statusIdx: index('posts_status_idx').on(table.status), })) export const postsRelations = relations(posts, ({ one }) => ({ author: one(users, { fields: [posts.authorId], references: [users.id], }), })) // --- Type Exports --- export type User = typeof users.$inferSelect export type NewUser = typeof users.$inferInsert export type Post = typeof posts.$inferSelect export type NewPost = typeof posts.$inferInsert # Column Patterns Complete reference for every Drizzle ORM column type used with Cloudflare D1. All patterns verified against real D1 projects. ## Imports ```typescript import { sqliteTable, text, integer, real, blob, index, uniqueIndex } from 'drizzle-orm/sqlite-core' import { relations, sql } from 'drizzle-orm' ``` ## Primary Keys ### Text UUID (preferred) ```typescript id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()), ``` Generates UUIDs at insert time. Works in Workers runtime (crypto.randomUUID is available). ### Integer Autoincrement ```typescript id: integer('id').primaryKey({ autoIncrement: true }), ``` Use when you need sequential IDs or when the table is insert-heavy and UUID overhead matters. ## Text ### Plain text ```typescript name: text('name').notNull(), description: text('description'), // nullable ``` ### Text with enum ```typescript role: text('role', { enum: ['admin', 'editor', 'viewer'] }).notNull().default('viewer'), status: text('status', { enum: ['draft', 'published', 'archived'] }).notNull().default('draft'), ``` Stored as TEXT in D1. Drizzle validates at the TypeScript level — no database-level constraint. ## Boolean D1 has no native BOOLEAN. Use INTEGER with `mode: 'boolean'`: ```typescript emailVerified: integer('e