/cloudflare-d1
Cloudflare D1 SQLite database with Workers, Drizzle ORM, migrations
Claude Code
$ npx -y skills add alinaqi/maggy --skill cloudflare-d1 --agent claude-code
Codex
$ npx skills add alinaqi/maggy --skill cloudflare-d1 -a codex -y
Cursor
$ npx skills add alinaqi/maggy --skill cloudflare-d1 -a cursor -y
Gemini CLI
$ npx skills add alinaqi/maggy --skill cloudflare-d1 -a gemini-cli -y
GitHub Copilot
$ npx skills add alinaqi/maggy --skill cloudflare-d1 -a github-copilot -y
OpenCode
$ npx skills add alinaqi/maggy --skill cloudflare-d1 -a opencode -y
Windsurf
$ npx skills add alinaqi/maggy --skill cloudflare-d1 -a windsurf -y
SKILL.md
cloudflare-d1.SKILL.mdname: cloudflare-d1
description: Cloudflare D1 SQLite database with Workers, Drizzle ORM, migrations
when-to-use: When working with Cloudflare D1 or Workers
user-invocable: false
paths: ["wrangler.toml", "src/worker*", "**/d1/**"]
effort: medium
Cloudflare D1 Skill
Cloudflare D1 is a serverless SQLite database designed for Cloudflare Workers with global distribution and zero cold starts.
**Sources:** [D1 Docs](https://developers.cloudflare.com/d1/) | [Drizzle + D1](https://orm.drizzle.team/docs/connect-cloudflare-d1) | [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/)
---
Core Principle
**SQLite at the edge, migrations in version control, Drizzle for type safety.**
D1 brings SQLite's simplicity to serverless. Design for horizontal scale (multiple small databases) rather than vertical (one large database). Use Drizzle ORM for type-safe queries and migrations.
---
D1 Stack
| Component | Purpose | |-----------|---------| | **D1** | Serverless SQLite database | | **Workers** | Edge runtime for your application | | **Wrangler** | CLI for development and deployment | | **Drizzle ORM** | Type-safe ORM with migrations | | **Drizzle Kit** | Migration tooling | | **Hono** | Lightweight web framework (optional) |
---
Project Setup
Create Worker Project
# Create new project
npm create cloudflare@latest my-app -- --template "worker-typescript"
cd my-app
# Install dependencies
npm install drizzle-orm
npm install -D drizzle-kit
Create D1 Database
# Create database (creates both local and remote)
npx wrangler d1 create my-database
# Output:
# [[d1_databases]]
# binding = "DB"
# database_name = "my-database"
# database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Configure wrangler.toml
name = "my-app"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
migrations_dir = "drizzle"
migrations_table = "drizzle_migrations"
Generate TypeScript Types
# Generate env types from wrangler.toml
npx wrangler types
# Creates worker-configuration.d.ts:
# interface Env {
# DB: D1Database;
# }---
Drizzle ORM Setup
Schema Definition
// src/db/schema.ts
import { sqliteTable, text, integer, real, blob } from 'drizzle-orm/sqlite-core';
import { sql } from 'drizzle-orm';
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
email: text('email').notNull().unique(),
name: text('name').notNull(),
role: text('role', { enum: ['user', 'admin'] }).default('user'),
createdAt: text('created_at').default(sql`CURRENT_TIMESTAMP`),
updatedAt: text('updated_at').default(sql`CURRENT_TIMESTAMP`)
});
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
content: text('content'),
authorId: integer('author_id').references(() => users.id),
published: integer('published', { mode: 'boolean' }).default(false),
viewCount: integer('view_count').default(0),
createdAt: text('created_at').default(sql`CURRENT_TIMESTAMP`)
});
export const tags = sqliteTable('tags', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull().unique()
});
export const postTags = sqliteTable('post_tags', {
postId: integer('post_id').references(() => posts.id),
tagId: integer('tag_id').references(() => tags.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;Drizzle Config
// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'sqlite',
driver: 'd1-http',
dbCredentials: {
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
token: process.env.CLOUDFLARE_D1_TOKEN!
}
});Database Client
// src/db/index.ts
import { drizzle } from 'drizzle-orm/d1';
import * as schema from './schema';
export function createDb(d1: D1Database) {
return drizzle(d1, { schema });
}
export type Database = ReturnType<typeof createDb>;
export * from './schema';---
Migration Workflow
Generate Migration
# Generate migration from schema changes
npx drizzle-kit generate
# Output: drizzle/0000_initial.sql
Apply Migrations Locally
# Apply to local D1
npx wrangler d1 migrations apply my-database --local
# Or via Drizzle
npx drizzle-kit migrate
Apply Migrations to Production
# Apply to remote D1
npx wrangler d1 migrations apply my-database --remote
# Preview first (dry run)
npx wrangler d1 migrations apply my-database --remote --dry-run
Migration File Example
-- drizzle/0000_initial.sql
CREATE TABLE `users` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`email` text NOT NULL,
`name` text NOT NULL,
`role` text DEFAULT 'user',
`created_at` text DEFAULT CURRENT_TIMESTAMP,
`updated_at` text DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);
CREATE TABLE `posts` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`title` text NOT NULL,
`content` text,
`author_id` integer REFERENCES `users`(`id`),
`published` integer DEFAULT false,
`view_count` integer DEFAULT 0,
`created_at` text DEFAULT CURRENT_TIMESTAMP
);
---
Worker Implementation
Basic Worker with Hono
// src/index.ts
import { Hono } from 'hono';
import { createDb, users, posts } from './db';
import { eq, desc } from 'drizzle-orm';
type Bindings = {
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
// Middleware to inject db
app.use('*', async (c, next)Read more
name: cloudflare-d1 description: Cloudflare D1 SQLite database with Workers, Drizzle ORM, migrations when-to-use: When working with Cloudflare D1 or Workers user-invocable: false paths: ["wrangler.toml", "src/worker*", "**/d1/**"] effort: medium
Cloudflare D1 Skill
Cloudflare D1 is a serverless SQLite database designed for Cloudflare Workers with global distribution and zero cold starts.
**Sources:** [D1 Docs](https://developers.cloudflare.com/d1/) | [Drizzle + D1](https://orm.drizzle.team/docs/connect-cloudflare-d1) | [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/)
---
Core Principle
**SQLite at the edge, migrations in version control, Drizzle for type safety.**
D1 brings SQLite's simplicity to serverless. Design for horizontal scale (multiple small databases) rather than vertical (one large database). Use Drizzle ORM for type-safe queries and migrations.
---
D1 Stack
| Component | Purpose | |-----------|---------| | **D1** | Serverless SQLite database | | **Workers** | Edge runtime for your application | | **Wrangler** | CLI for development and deployment | | **Drizzle ORM** | Type-safe ORM with migrations | | **Drizzle Kit** | Migration tooling | | **Hono** | Lightweight web framework (optional) |
---
Project Setup
Create Worker Project
# Create new project npm create cloudflare@latest my-app -- --template "worker-typescript" cd my-app # Install dependencies npm install drizzle-orm npm install -D drizzle-kit
Create D1 Database
# Create database (creates both local and remote) npx wrangler d1 create my-database # Output: # [[d1_databases]] # binding = "DB" # database_name = "my-database" # database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Configure wrangler.toml
name = "my-app" main = "src/index.ts" compatibility_date = "2024-01-01" [[d1_databases]] binding = "DB" database_name = "my-database" database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" migrations_dir = "drizzle" migrations_table = "drizzle_migrations"
Generate TypeScript Types
# Generate env types from wrangler.toml
npx wrangler types
# Creates worker-configuration.d.ts:
# interface Env {
# DB: D1Database;
# }---
Drizzle ORM Setup
Schema Definition
// src/db/schema.ts
import { sqliteTable, text, integer, real, blob } from 'drizzle-orm/sqlite-core';
import { sql } from 'drizzle-orm';
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
email: text('email').notNull().unique(),
name: text('name').notNull(),
role: text('role', { enum: ['user', 'admin'] }).default('user'),
createdAt: text('created_at').default(sql`CURRENT_TIMESTAMP`),
updatedAt: text('updated_at').default(sql`CURRENT_TIMESTAMP`)
});
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
content: text('content'),
authorId: integer('author_id').references(() => users.id),
published: integer('published', { mode: 'boolean' }).default(false),
viewCount: integer('view_count').default(0),
createdAt: text('created_at').default(sql`CURRENT_TIMESTAMP`)
});
export const tags = sqliteTable('tags', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull().unique()
});
export const postTags = sqliteTable('post_tags', {
postId: integer('post_id').references(() => posts.id),
tagId: integer('tag_id').references(() => tags.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;Drizzle Config
// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'sqlite',
driver: 'd1-http',
dbCredentials: {
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
token: process.env.CLOUDFLARE_D1_TOKEN!
}
});Database Client
// src/db/index.ts
import { drizzle } from 'drizzle-orm/d1';
import * as schema from './schema';
export function createDb(d1: D1Database) {
return drizzle(d1, { schema });
}
export type Database = ReturnType<typeof createDb>;
export * from './schema';---
Migration Workflow
Generate Migration
# Generate migration from schema changes npx drizzle-kit generate # Output: drizzle/0000_initial.sql
Apply Migrations Locally
# Apply to local D1 npx wrangler d1 migrations apply my-database --local # Or via Drizzle npx drizzle-kit migrate
Apply Migrations to Production
# Apply to remote D1 npx wrangler d1 migrations apply my-database --remote # Preview first (dry run) npx wrangler d1 migrations apply my-database --remote --dry-run
Migration File Example
-- drizzle/0000_initial.sql CREATE TABLE `users` ( `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `email` text NOT NULL, `name` text NOT NULL, `role` text DEFAULT 'user', `created_at` text DEFAULT CURRENT_TIMESTAMP, `updated_at` text DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`); CREATE TABLE `posts` ( `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `title` text NOT NULL, `content` text, `author_id` integer REFERENCES `users`(`id`), `published` integer DEFAULT false, `view_count` integer DEFAULT 0, `created_at` text DEFAULT CURRENT_TIMESTAMP );
---
Worker Implementation
Basic Worker with Hono
// src/index.ts
import { Hono } from 'hono';
import { createDb, users, posts } from './db';
import { eq, desc } from 'drizzle-orm';
type Bindings = {
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
// Middleware to inject db
app.use('*', async (c, next)Turn Claude Code into a self-reviewing, test-enforced engineering system that remembers context across sessions — then route work across 13 models from a single dashboard.
Other skills on maggy.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about cloudflare-d1.
- Which coding agents can use cloudflare-d1?
- cloudflare-d1 installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

