关于 cloudflare-d1
cloudflare-d1 是面向 Cloudflare Workers 开发者的 D1 数据库操作指南,介绍数据库绑定、SQL 查询和迁移流程。内容还涵盖本地与远程开发、批量查询及常见错误处理。
主要功能
- 01Wrangler 数据库创建与绑定
- 02版本化 SQL 迁移
- 03预处理语句与批量查询
- 04本地和远程数据库操作
- 05错误重试与查询优化
适用场景
- 01为 Worker 配置 D1 数据库
- 02创建并应用模式迁移
- 03批量执行关联数据查询
- 04排查数据库错误并优化查询
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill cloudflare-d1安装后在 Claude Code 中输入/cloudflare-d1确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.md.claude-plugin/plugin.jsonreferences/best-practices.mdquery-patterns.mdrules/cloudflare-d1.mdtemplates/d1-setup-migration.shd1-worker-queries.tsschema-example.sql详细介绍
Cloudflare D1 数据库
状态:已可用于生产环境 ✅ 最后更新:2026-01-20 依赖项:cloudflare-worker-base(用于 Worker 设置) 最新版本:[email protected],@cloudflare/[email protected]
近期更新(2025):
- 2025 年 11 月:支持司法管辖区(符合数据本地化要求),远程绑定正式推出([email protected]+),自动配置资源
- 2025 年 9 月:自动重试只读查询(最多 2 次),远程绑定公开测试版
- 2025 年 7 月:存储限额提升(250GB → 1TB),移除 Alpha 版备份访问权限,REST API 快 50-500ms
- 2025 年 5 月:修复 HTTP API 权限安全问题(写入需要 D1:Edit 权限)
- 2025 年 4 月:读取副本公开测试版(跨区域只读副本)
- 2025 年 2 月:支持 PRAGMA optimize,修复只读访问权限错误
- 2025 年 1 月:开始执行免费套餐限额(2 月 10 日起),Worker API 查询速度提升 40-60%
快速入门(5 分钟)
1. 创建 D1 数据库
# Create a new D1 database
npx wrangler d1 create my-database
# Output includes database_id - save this!
# ✅ Successfully created DB 'my-database'
#
# [[d1_databases]]
# binding = "DB"
# database_name = "my-database"
# database_id = "<UUID>"
2. 配置绑定
将以下内容添加到 wrangler.jsonc:
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-10-11",
"d1_databases": [
{
"binding": "DB", // Available as env.DB in your Worker
"database_name": "my-database", // Name from wrangler d1 create
"database_id": "<UUID>", // ID from wrangler d1 create
"preview_database_id": "local-db" // For local development
}
]
}
重要:
binding是你在代码中访问数据库的方式(env.DB)database_id是生产数据库的 UUIDpreview_database_id用于本地开发(可以是任意字符串)- 切勿将真实的
database_id值提交到公共代码仓库——请使用环境变量或密钥
3. 创建第一个迁移
# Create migration file
npx wrangler d1 migrations create my-database create_users_table
# This creates: migrations/0001_create_users_table.sql
编辑迁移文件:
-- migrations/0001_create_users_table.sql
DROP TABLE IF EXISTS users;
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
username TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER
);
-- Create index for common queries
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
-- Optimize database
PRAGMA optimize;
4. 应用迁移
# Apply locally first (for testing)
npx wrangler d1 migrations apply my-database --local
# Apply to production when ready
npx wrangler d1 migrations apply my-database --remote
5. 从 Worker 查询
// src/index.ts
import { Hono } from 'hono';
type Bindings = {
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
app.get('/api/users/:email', async (c) => {
const email = c.req.param('email');
try {
// ALWAYS use prepared statements with bind()
const result = await c.env.DB.prepare(
'SELECT * FROM users WHERE email = ?'
)
.bind(email)
.first();
if (!result) {
return c.json({ error: 'User not found' }, 404);
}
return c.json(result);
} catch (error: any) {
console.error('D1 Error:', error.message);
return c.json({ error: 'Database error' }, 500);
}
});
export default app;
D1 迁移系统
迁移工作流
# 1. Create migration
npx wrangler d1 migrations create <DATABASE_NAME> <MIGRATION_NAME>
# 2. List unapplied migrations
npx wrangler d1 migrations list <DATABASE_NAME> --local
npx wrangler d1 migrations list <DATABASE_NAME> --remote
# 3. Apply migrations
npx wrangler d1 migrations apply <DATABASE_NAME> --local # Test locally
npx wrangler d1 migrations apply <DATABASE_NAME> --remote # Deploy to production
迁移文件命名
迁移会自动进行版本管理:
migrations/
├── 0000_initial_schema.sql
├── 0001_add_users_table.sql
├── 0002_add_posts_table.sql
└── 0003_add_indexes.sql
规则:
- 文件按顺序依次执行
- 每个迁移只运行一次(记录在
d1_migrations表中) - 失败的迁移会回滚(事务处理)
- 不能修改或删除已应用的迁移
自定义迁移配置
{
"d1_databases": [
{
"binding": "DB",
"database_name": "my-database",
"database_id": "<UUID>",
"migrations_dir": "db/migrations", // Custom directory (default: migrations/)
"migrations_table": "schema_migrations" // Custom tracking table (default: d1_migrations)
}
]
}
迁移最佳实践
✅ 务必做到:
-- Use IF NOT EXISTS to make migrations idempotent
CREATE TABLE IF NOT EXISTS users (...);
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
-- Run PRAGMA optimize after schema changes
PRAGMA optimize;
-- Use UPPERCASE BEGIN/END in triggers (lowercase fails remotely)
CREATE TRIGGER update_timestamp
AFTER UPDATE ON users
FOR EACH ROW
BEGIN
UPDATE users SET updated_at = unixepoch() WHERE user_id = NEW.user_id;
END;
-- Use transactions for data migrations
BEGIN TRANSACTION;
UPDATE users SET updated_at = unixepoch() WHERE updated_at IS NULL;
COMMIT;
❌ 切勿这样做:
-- DON'T include BEGIN TRANSACTION at start of migration file (D1 handles this)
BEGIN TRANSACTION; -- ❌ Remove this
-- DON'T use lowercase begin/end in triggers (works locally, FAILS remotely)
CREATE TRIGGER my_trigger
AFTER INSERT ON table
begin -- ❌ Use BEGIN (uppercase)
UPDATE ...;
end; -- ❌ Use END (uppercase)
-- DON'T use MySQL/PostgreSQL syntax
ALTER TABLE users MODIFY COLUMN email VARCHAR(255); -- ❌ Not SQLite
-- DON'T create tables without IF NOT EXISTS
CREATE TABLE users (...); -- ❌ Fails if table exists
在迁移中处理外键
-- Temporarily disable foreign key checks during schema changes
PRAGMA defer_foreign_keys = true;
-- Make schema changes that would violate foreign keys
ALTER TABLE posts DROP COLUMN author_id;
ALTER TABLE posts ADD COLUMN user_id INTEGER REFERENCES users(user_id);
-- Foreign keys re-enabled automatically at end of migration
D1 Workers API
类型定义:
interface Env { DB: D1Database; }
type Bindings = { DB: D1Database; };
const app = new Hono<{ Bindings: Bindings }>();
prepare() - 主要方法(处理用户输入时务必使用):
const user = await env.DB.prepare('SELECT * FROM users WHERE email = ?')
.bind(email).first();
原因:可防止 SQL 注入、可重复使用、性能更佳且类型安全
查询结果方法:
.all()→{ results, meta }- 获取所有行.first()→ 行对象或 null - 获取第一行.first('column')→ 值 - 获取单列的值(例如 COUNT).run()→{ success, meta }- 执行 INSERT/UPDATE/DELETE(不返回结果)
batch() - 对性能至关重要:
const results = await env.DB.batch([
env.DB.prepare('SELECT * FROM users WHERE user_id = ?').bind(1),
env.DB.prepare('SELECT * FROM posts WHERE user_id = ?').bind(1)
]);
- 按顺序执行,只需一次网络往返
- 如果其中一条语句失败,剩余语句不会执行
- 适用于:批量插入、获取相关数据
exec() - 避免在生产环境中使用:
await env.DB.exec('SELECT * FROM users;'); // Only for migrations/maintenance
- ❌ 切勿与用户输入一起使用(有 SQL 注入风险)
- ✅ 仅用于:迁移文件、一次性任务
查询模式
基本 CRUD 操作
// CREATE
const { meta } = await env.DB.prepare(
'INSERT INTO users (email, username, created_at) VALUES (?, ?, ?)'
).bind(email, username, Date.now()).run();
const newUserId = meta.last_row_id;
// READ (single)
const user = await env.DB.prepare('SELECT * FROM users WHERE user_id = ?')
.bind(userId).first();
// READ (multiple)
const { results } = await env.DB.prepare('SELECT * FROM users LIMIT ?')
.bind(10).all();
// UPDATE
const { meta } = await env.DB.prepare('UPDATE users SET username = ? WHERE user_id = ?')
.bind(newUsername, userId).run();
const rowsAffected = meta.rows_written;
// DELETE
await env.DB.prepare('DELETE FROM users WHERE user_id = ?').bind(userId).run();
// COUNT
const count = await env.DB.prepare('SELECT COUNT(*) as total FROM users').first('total');
// EXISTS check
const exists = await env.DB.prepare('SELECT 1 FROM users WHERE email = ? LIMIT 1')
.bind(email).first();
分页模式
const page = parseInt(c.req.query('page') || '1');
const limit = 20;
const offset = (page - 1) * limit;
const [countResult, usersResult] = await c.env.DB.batch([
c.env.DB.prepare('SELECT COUNT(*) as total FROM users'),
c.env.DB.prepare('SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?')
.bind(limit, offset)
]);
return c.json({
users: usersResult.results,
pagination: { page, limit, total: countResult.results[0].total }
});
批处理模式(伪事务)
// D1 doesn't support multi-statement transactions, but batch() provides sequential execution
await env.DB.batch([
env.DB.prepare('UPDATE users SET credits = credits - ? WHERE user_id = ?').bind(amount, fromUserId),
env.DB.prepare('UPDATE users SET credits = credits + ? WHERE user_id = ?').bind(amount, toUserId),
env.DB.prepare('INSERT INTO transactions (from_user, to_user, amount) VALUES (?, ?, ?)').bind(fromUserId, toUserId, amount)
]);
// If any statement fails, batch stops (transaction-like behavior)
错误处理
常见错误类型:
D1_ERROR- 常规 D1 错误(通常是暂时性的)D1_EXEC_ERROR- SQL 语法错误或功能限制D1_TYPE_ERROR- 类型不匹配(使用了 undefined 而不是 null)D1_COLUMN_NOTFOUND- 列不存在
常见错误及解决方法:
| 错误 | 原因 | 解决方法 |
|---|---|---|
| 语句过长 | INSERT 包含 1000 行以上数据 | 使用 batch() 分成每批 100-250 行 |
| 网络连接断开 | 暂时性故障或导入数据量过大 | 实现重试逻辑(见下文)或拆分成更小的数据块 |
| 排队的请求过多 | 在循环中执行单条查询 | 使用 batch() 代替循环 |
| D1_TYPE_ERROR | 在 bind 中使用 undefined | 可选值使用 null:.bind(email, bio || null) |
| 事务冲突 | 在迁移中使用 BEGIN TRANSACTION | 移除 BEGIN/COMMIT(D1 会自动处理) |
| 外键约束冲突 | 架构更改破坏了约束 | 使用 PRAGMA defer_foreign_keys = true |
| D1_EXEC_ERROR: incomplete input | 在 D1Database.exec() 中使用多行 SQL | 使用预处理语句或外部 .sql 文件(问题 #9133) |
暂时性错误属于预期行为
重要:D1 查询可能会暂时失败,并出现“Network connection lost”、“storage operation exceeded timeout”或“isolate exceeded its memory limit”等错误。Cloudflare 文档指出,“每隔几小时出现少量错误并不意外”,并建议实现重试逻辑。(D1 常见问题)
常见暂时性错误:
D1_ERROR: Network connection lostD1 DB storage operation exceeded timeout which caused object to be resetInternal error while starting up D1 DB storage caused object to be resetD1 DB's isolate exceeded its memory limit and was reset
重试模式(推荐):
async function queryWithRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = 100
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error: any) {
const isTransient = error.message?.includes('Network connection lost') ||
error.message?.includes('exceeded timeout') ||
error.message?.includes('exceeded its memory limit');
if (!isTransient || i === maxRetries - 1) throw error;
// Exponential backoff
await new Promise(r => setTimeout(r, baseDelay * Math.pow(2, i)));
}
}
throw new Error('Max retries exceeded');
}
// Usage
const user = await queryWithRetry(() =>
env.DB.prepare('SELECT * FROM users WHERE email = ?').bind(email).first()
);
自动重试(2025 年 9 月):
D1 会在可重试错误发生时,自动重试只读查询(SELECT、EXPLAIN、WITH),最多 2 次。检查响应中的 meta.total_attempts 以查看重试次数。写入查询仍应实现自定义重试逻辑。
性能优化
索引最佳实践:
- ✅ 为 WHERE 子句中的列创建索引:
CREATE INDEX idx_users_email ON users(email) - ✅ 为外键创建索引:
CREATE INDEX idx_posts_user_id ON posts(user_id) - ✅ 为用于排序的列创建索引:
CREATE INDEX idx_posts_created_at ON posts(created_at DESC) - ✅ 多列索引:
CREATE INDEX idx_posts_user_published ON posts(user_id, published) - ✅ 部分索引:
CREATE INDEX idx_users_active ON users(email) WHERE deleted = 0 - ✅ 使用以下语句进行测试:
EXPLAIN QUERY PLAN SELECT ...
PRAGMA optimize(2025 年 2 月):
CREATE INDEX idx_users_email ON users(email);
PRAGMA optimize; -- Run after schema changes
查询优化:
- ✅ 使用指定列(而不是
SELECT *) - ✅ 对大型结果集始终使用 LIMIT
- ✅ 在 WHERE 条件中使用索引
- ❌ 避免在 WHERE 中使用函数(无法使用索引):
WHERE LOWER(email)→ 改为存储小写值
本地开发
本地与远程(2025 年 11 月——远程绑定正式推出):
# Local database (automatic creation)
npx wrangler d1 migrations apply my-database --local
npx wrangler d1 execute my-database --local --command "SELECT * FROM users"
# Remote database
npx wrangler d1 execute my-database --remote --command "SELECT * FROM users"
# Remote bindings ([email protected]+) - connect local Worker to deployed D1
# Add to wrangler.jsonc: { "binding": "DB", "remote": true }
远程绑定连接超时
已知问题:使用远程 D1 绑定({ "remote": true })时,连接会在闲置恰好 1 小时后超时。(GitHub 问题 #10801)
错误:D1_ERROR: Failed to parse body as JSON, got: error code: 1031
解决方法:
// Keep connection alive with periodic query (optional)
setInterval(async () => {
try {
await env.DB.prepare('SELECT 1').first();
} catch (e) {
console.log('Connection keepalive failed:', e);
}
}, 30 * 60 * 1000); // Every 30 minutes
或者,如果闲置 1 小时后查询失败,只需重启开发服务器。
多 Worker 开发(服务绑定)
在单个 wrangler dev 进程中运行多个带有服务绑定的 Worker 时,辅助 Worker 无法访问其 D1 绑定,因为两个 Worker 共用同一个持久化路径。(GitHub Issue #11121)
解决方案:使用 --persist-to 标志,让所有 Worker 指向同一个持久化存储:
# Apply worker2 migrations to worker1's persistence path
cd worker2
npx wrangler d1 migrations apply DB --local --persist-to=../worker1/.wrangler/state
# Now both workers can access D1
cd ../worker1
npx wrangler dev # Both workers share the same D1 data
本地数据库位置:
.wrangler/state/v3/d1/miniflare-D1DatabaseObject/<database_id>.sqlite
为本地数据库填充初始数据:
npx wrangler d1 execute my-database --local --file=seed.sql
扩展与限制
10 GB 数据库大小限制——分片模式
D1 对单个数据库有严格的 10 GB 限制,但 Cloudflare 支持每个 Worker 最多关联 50,000 个数据库。使用分片可扩展至 10 GB 以上。(DEV.to Article)
基于哈希的分片示例(10 个数据库 = 100 GB 容量):
// Hash user ID to shard number
function getShardId(userId: string): number {
const hash = Array.from(userId).reduce((acc, char) =>
((acc << 5) - acc) + char.charCodeAt(0), 0
);
return Math.abs(hash) % 10; // 10 shards
}
// wrangler.jsonc - Define 10 database shards
{
"d1_databases": [
{ "binding": "DB_SHARD_0", "database_id": "..." },
{ "binding": "DB_SHARD_1", "database_id": "..." },
{ "binding": "DB_SHARD_2", "database_id": "..." },
// ... up to DB_SHARD_9
]
}
// Get correct shard for user
function getUserDb(env: Env, userId: string): D1Database {
const shardId = getShardId(userId);
return env[`DB_SHARD_${shardId}`];
}
// Query user's data from correct shard
const db = getUserDb(env, userId);
const user = await db.prepare('SELECT * FROM users WHERE user_id = ?')
.bind(userId).first();
替代方案:基于租户分片(每位客户/每个租户使用一个数据库)
2 MB 行大小限制——D1 + R2 混合模式
D1 的行大小限制为 2 MB。对于大型内容(HTML、JSON、图像),使用 R2 存储内容,并用 D1 存储元数据。(DEV.to Article)
错误:database row size exceeded maximum allowed size
解决方案——混合存储模式:
// 1. Store large content in R2
const contentKey = `pages/${crypto.randomUUID()}.html`;
await env.R2_BUCKET.put(contentKey, largeHtmlContent);
// 2. Store metadata in D1
await env.DB.prepare(`
INSERT INTO pages (url, r2_key, size, created_at)
VALUES (?, ?, ?, ?)
`).bind(url, contentKey, largeHtmlContent.length, Date.now()).run();
// 3. Retrieve content
const page = await env.DB.prepare('SELECT * FROM pages WHERE url = ?')
.bind(url).first();
if (page) {
const content = await env.R2_BUCKET.get(page.r2_key);
const html = await content.text();
}
数据库可移植性——迁移至 PostgreSQL 的注意事项
如果你计划之后从 D1(SQLite)迁移到 Hyperdrive(PostgreSQL),请统一使用小写命名。PostgreSQL 的表名和列名区分大小写,而 SQLite 不区分。(Mats' Blog)
-- Use lowercase for portability
CREATE TABLE users (user_id INTEGER, email TEXT);
CREATE INDEX idx_users_email ON users(email);
-- NOT: CREATE TABLE Users (UserId INTEGER, Email TEXT);
FTS5 全文搜索
大小写敏感性:创建虚拟表时务必使用小写的“fts5”。大写形式可能导致“not authorized”错误。(Cloudflare Community)
-- Correct
CREATE VIRTUAL TABLE search_index USING fts5(
title,
content,
tokenize = 'porter unicode61'
);
-- Query the index
SELECT * FROM search_index WHERE search_index MATCH 'query terms';
导出限制:包含 FTS5 虚拟表的数据库无法使用 wrangler d1 export 导出。导出前请先删除虚拟表,再在导入后重新创建。(GitHub Issue #9519)
大型导入/导出操作
大型导入时的网络超时:包含 5000 条以上 INSERT 语句的文件可能会因“Network connection lost”错误而失败。(GitHub Issue #11958)
解决方案:
- 将大文件拆分成较小的文件(每个文件少于 5000 条语句)
- 使用 Worker 的
batch()API,而不是 wrangler CLI - 先导入到本地,再使用 Time Travel 恢复到远程
- 减小单条语句的大小(每条 INSERT 包含 100-250 行)
Windows 特有问题:在 Windows 11 上,从 D1 导出的大型 SQL 文件重新导入时可能会因“HashIndex detected hash table inconsistency”错误而失败。(GitHub Issue #11708)
变通方法:执行前删除 .wrangler 目录:
rm -rf .wrangler
npx wrangler d1 execute db-name --file=database.sql
最佳实践总结
✅ 务必做到:
- 使用预处理语句和
.bind()处理用户输入 - 使用
.batch()执行多个查询(降低延迟) - 为经常查询的列创建索引
- 更改架构后运行
PRAGMA optimize - 在迁移中使用
IF NOT EXISTS,确保操作幂等 - 应用到生产环境前,在本地测试迁移
- 使用 try/catch 妥善处理错误
- 可选值使用
null,而不是undefined - 将输入绑定到查询前先进行验证
- UPDATE/DELETE 后检查
meta.rows_written
❌ 切勿:
- 切勿对用户输入使用
.exec()(有 SQL 注入风险) - 切勿在公开代码库中硬编码
database_id - 切勿在绑定参数中使用
undefined(会导致 D1_TYPE_ERROR) - 切勿在循环中逐条执行查询(请改用批处理)
- 切勿忘记为可能返回大量结果的查询添加
LIMIT - 切勿在生产环境中使用
SELECT *(请指定列) - 切勿在迁移文件中包含
BEGIN TRANSACTION - 切勿修改已应用的迁移(请创建新的迁移)
- 切勿跳过数据库操作的错误处理
- 切勿假定查询一定成功(务必检查结果)
已避免的已知问题
此技能可避免 14 个有记录的 D1 错误:
| 问题编号 | 错误/问题 | 描述 | 避免方法 | 来源 |
|---|---|---|---|---|
| #1 | 语句过长 | 大型 INSERT 语句超出 D1 限制 | 使用 batch() 将数据拆分为每批 100-250 行 | 已有 |
| #2 | 事务冲突 | 在迁移文件中使用 BEGIN TRANSACTION | 移除 BEGIN/COMMIT(D1 会自动处理) | 已有 |
| #3 | 外键约束违规 | 架构变更破坏外键约束 | 在迁移中使用 PRAGMA defer_foreign_keys = true | 已有 |
| #4 | 速率限制 / 队列过载 | 逐条执行的查询过多 | 使用 batch() 代替循环 | 已有 |
| #5 | 超出内存限制 | 查询将过多数据加载到内存中 | 添加 LIMIT、对结果分页、拆分查询 | 已有 |
| #6 | 类型不匹配错误 | 在 bind() 中使用 undefined 而不是 null | 可选值始终使用 null | 已有 |
| #7 | 触发器中的 BEGIN 为小写 | 远程执行时,包含小写 begin/end 的触发器会失败 | 使用大写 BEGIN/END 关键字(问题 #10998) | TIER 1 |
| #8 | 远程绑定超时 | 连接闲置 1 小时后超时 | 重启开发服务器或实现保活模式(问题 #10801) | TIER 1 |
| #9 | 服务绑定无法访问 D1 | 多工作进程开发环境中的辅助 Worker 无法访问 D1 | 使用 --persist-to 标志共享持久化路径(问题 #11121) | TIER 1 |
| #10 | 瞬时网络错误 | 随机出现“网络连接已断开”故障 | 实现指数退避重试逻辑(D1 常见问题) | TIER 1 |
| #11 | FTS5 导致导出失败 | 包含 FTS5 虚拟表的数据库无法导出 | 导出前删除虚拟表,导入后重新创建(问题 #9519) | TIER 1 |
| #12 | exec() 中的多行 SQL | D1Database.exec() 无法执行多行 SQL | 使用预处理语句或外部 .sql 文件(问题 #9133) | TIER 1 |
| #13 | 10 GB 数据库限制 | 单个数据库限制为 10 GB | 在多个数据库间实施分片(社区) | TIER 2 |
| #14 | 2 MB 行大小限制 | 超过 2 MB 的行会导致失败 | 使用 D1 + R2 混合存储模式(社区) | TIER 2 |
Wrangler 命令参考
# Database management
wrangler d1 create <DATABASE_NAME>
wrangler d1 list
wrangler d1 delete <DATABASE_NAME>
wrangler d1 info <DATABASE_NAME>
# Migrations
wrangler d1 migrations create <DATABASE_NAME> <MIGRATION_NAME>
wrangler d1 migrations list <DATABASE_NAME> --local|--remote
wrangler d1 migrations apply <DATABASE_NAME> --local|--remote
# Execute queries
wrangler d1 execute <DATABASE_NAME> --local|--remote --command "SELECT * FROM users"
wrangler d1 execute <DATABASE_NAME> --local|--remote --file=./query.sql
# Time Travel (view historical data)
wrangler d1 time-travel info <DATABASE_NAME> --timestamp "2025-10-20"
wrangler d1 time-travel restore <DATABASE_NAME> --timestamp "2025-10-20"
官方文档
- D1 概览:https://developers.cloudflare.com/d1/
- 入门指南:https://developers.cloudflare.com/d1/get-started/
- 迁移:https://developers.cloudflare.com/d1/reference/migrations/
- Workers API:https://developers.cloudflare.com/d1/worker-api/
- 最佳实践:https://developers.cloudflare.com/d1/best-practices/
- Wrangler 命令:https://developers.cloudflare.com/workers/wrangler/commands/#d1
准备好使用 D1 开始构建了! 🚀
上次验证时间:2026-01-20 | 技能版本:3.0.0 | 变更:根据社区调研新增 8 个已知问题(TIER 1-2 发现):触发器的大小写敏感性、远程绑定超时、多 Worker 开发模式、瞬态错误处理、FTS5 限制、分片模式、D1+R2 混合存储,以及数据库可移植性考量。