$npx -y skills add jackspace/ClaudeSkillz --skill cloudflare-d1Complete knowledge domain for Cloudflare D1 - serverless SQLite database on Cloudflare's edge network. Use when: creating D1 databases, writing SQL migrations, configuring D1 bindings, querying D1 from Workers, handling SQLite data, building relational data models, or encounterin
| 1 | # Cloudflare D1 Database |
| 2 | |
| 3 | **Status**: Production Ready ✅ |
| 4 | **Last Updated**: 2025-10-21 |
| 5 | **Dependencies**: cloudflare-worker-base (for Worker setup) |
| 6 | **Latest Versions**: wrangler@4.43.0, @cloudflare/workers-types@4.20251014.0 |
| 7 | |
| 8 | --- |
| 9 | |
| 10 | ## Quick Start (5 Minutes) |
| 11 | |
| 12 | ### 1. Create D1 Database |
| 13 | |
| 14 | ```bash |
| 15 | # Create a new D1 database |
| 16 | npx wrangler d1 create my-database |
| 17 | |
| 18 | # Output includes database_id - save this! |
| 19 | # ✅ Successfully created DB 'my-database' |
| 20 | # |
| 21 | # [[d1_databases]] |
| 22 | # binding = "DB" |
| 23 | # database_name = "my-database" |
| 24 | # database_id = "<UUID>" |
| 25 | ``` |
| 26 | |
| 27 | ### 2. Configure Bindings |
| 28 | |
| 29 | Add to your `wrangler.jsonc`: |
| 30 | |
| 31 | ```jsonc |
| 32 | { |
| 33 | "name": "my-worker", |
| 34 | "main": "src/index.ts", |
| 35 | "compatibility_date": "2025-10-11", |
| 36 | "d1_databases": [ |
| 37 | { |
| 38 | "binding": "DB", // Available as env.DB in your Worker |
| 39 | "database_name": "my-database", // Name from wrangler d1 create |
| 40 | "database_id": "<UUID>", // ID from wrangler d1 create |
| 41 | "preview_database_id": "local-db" // For local development |
| 42 | } |
| 43 | ] |
| 44 | } |
| 45 | ``` |
| 46 | |
| 47 | **CRITICAL:** |
| 48 | - `binding` is how you access the database in code (`env.DB`) |
| 49 | - `database_id` is the production database UUID |
| 50 | - `preview_database_id` is for local dev (can be any string) |
| 51 | - **Never commit real `database_id` values to public repos** - use environment variables or secrets |
| 52 | |
| 53 | ### 3. Create Your First Migration |
| 54 | |
| 55 | ```bash |
| 56 | # Create migration file |
| 57 | npx wrangler d1 migrations create my-database create_users_table |
| 58 | |
| 59 | # This creates: migrations/0001_create_users_table.sql |
| 60 | ``` |
| 61 | |
| 62 | Edit the migration file: |
| 63 | |
| 64 | ```sql |
| 65 | -- migrations/0001_create_users_table.sql |
| 66 | DROP TABLE IF EXISTS users; |
| 67 | CREATE TABLE IF NOT EXISTS users ( |
| 68 | user_id INTEGER PRIMARY KEY AUTOINCREMENT, |
| 69 | email TEXT NOT NULL UNIQUE, |
| 70 | username TEXT NOT NULL, |
| 71 | created_at INTEGER NOT NULL, |
| 72 | updated_at INTEGER |
| 73 | ); |
| 74 | |
| 75 | -- Create index for common queries |
| 76 | CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); |
| 77 | |
| 78 | -- Optimize database |
| 79 | PRAGMA optimize; |
| 80 | ``` |
| 81 | |
| 82 | ### 4. Apply Migration |
| 83 | |
| 84 | ```bash |
| 85 | # Apply locally first (for testing) |
| 86 | npx wrangler d1 migrations apply my-database --local |
| 87 | |
| 88 | # Apply to production when ready |
| 89 | npx wrangler d1 migrations apply my-database --remote |
| 90 | ``` |
| 91 | |
| 92 | ### 5. Query from Your Worker |
| 93 | |
| 94 | ```typescript |
| 95 | // src/index.ts |
| 96 | import { Hono } from 'hono'; |
| 97 | |
| 98 | type Bindings = { |
| 99 | DB: D1Database; |
| 100 | }; |
| 101 | |
| 102 | const app = new Hono<{ Bindings: Bindings }>(); |
| 103 | |
| 104 | app.get('/api/users/:email', async (c) => { |
| 105 | const email = c.req.param('email'); |
| 106 | |
| 107 | try { |
| 108 | // ALWAYS use prepared statements with bind() |
| 109 | const result = await c.env.DB.prepare( |
| 110 | 'SELECT * FROM users WHERE email = ?' |
| 111 | ) |
| 112 | .bind(email) |
| 113 | .first(); |
| 114 | |
| 115 | if (!result) { |
| 116 | return c.json({ error: 'User not found' }, 404); |
| 117 | } |
| 118 | |
| 119 | return c.json(result); |
| 120 | } catch (error: any) { |
| 121 | console.error('D1 Error:', error.message); |
| 122 | return c.json({ error: 'Database error' }, 500); |
| 123 | } |
| 124 | }); |
| 125 | |
| 126 | export default app; |
| 127 | ``` |
| 128 | |
| 129 | --- |
| 130 | |
| 131 | ## D1 Migrations System |
| 132 | |
| 133 | ### Migration Workflow |
| 134 | |
| 135 | ```bash |
| 136 | # 1. Create migration |
| 137 | npx wrangler d1 migrations create <DATABASE_NAME> <MIGRATION_NAME> |
| 138 | |
| 139 | # 2. List unapplied migrations |
| 140 | npx wrangler d1 migrations list <DATABASE_NAME> --local |
| 141 | npx wrangler d1 migrations list <DATABASE_NAME> --remote |
| 142 | |
| 143 | # 3. Apply migrations |
| 144 | npx wrangler d1 migrations apply <DATABASE_NAME> --local # Test locally |
| 145 | npx wrangler d1 migrations apply <DATABASE_NAME> --remote # Deploy to production |
| 146 | ``` |
| 147 | |
| 148 | ### Migration File Naming |
| 149 | |
| 150 | Migrations are automatically versioned: |
| 151 | |
| 152 | ``` |
| 153 | migrations/ |
| 154 | ├── 0000_initial_schema.sql |
| 155 | ├── 0001_add_users_table.sql |
| 156 | ├── 0002_add_posts_table.sql |
| 157 | └── 0003_add_indexes.sql |
| 158 | ``` |
| 159 | |
| 160 | **Rules:** |
| 161 | - Files are executed in sequential order |
| 162 | - Each migration runs once (tracked in `d1_migrations` table) |
| 163 | - Failed migrations roll back (transactional) |
| 164 | - Can't modify or delete applied migrations |
| 165 | |
| 166 | ### Custom Migration Configuration |
| 167 | |
| 168 | ```jsonc |
| 169 | { |
| 170 | "d1_databases": [ |
| 171 | { |
| 172 | "binding": "DB", |
| 173 | "database_name": "my-database", |
| 174 | "database_id": "<UUID>", |
| 175 | "migrations_dir": "db/migrations", // Custom directory (default: migrations/) |
| 176 | "migrations_table": "schema_migrations" // Custom tracking table (default: d1_migrations) |
| 177 | } |
| 178 | ] |
| 179 | } |
| 180 | ``` |
| 181 | |
| 182 | ### Migration Best Practices |