两个 Preview 绑定到相同的账户级资源 ID 或名称时,会共享其数据或实例。将 Preview 绑定到不同资源即可隔离它。
下表显示哪些资源会自动预配,哪些需要单独的资源绑定:
资源或 previews 字段 |
行为 | 隔离单个 Preview |
|---|---|---|
| Durable Objects | 为每个 Preview 自动预配新的 Durable Object namespace 和存储。 | 自动。 |
| Containers | 为每个 Preview 自动预配新的 container 应用和 container 实例。 | 自动。 |
kv_namespaces |
按 id 绑定到 KV namespace。两个 Preview 共享同一 id 时共享 namespace 数据。 |
绑定到不同的 KV namespace。 |
d1_databases |
按 database_id 绑定到 D1 数据库。两个 Preview 共享同一 database_id 时共享行。 |
绑定到不同的 D1 数据库。 |
r2_buckets |
按 bucket_name 绑定到 R2 bucket。两个 Preview 共享同一 bucket_name 时共享对象。 |
绑定到不同的 R2 bucket。 |
queues.producers |
按名称将 Queue 生产者绑定到队列。两个 Preview 共享同一队列名称时会发送到同一队列。 | 绑定到不同的队列。 |
vectorize |
按 index_name 绑定到 Vectorize 索引。必须在部署前手动创建。 |
绑定到不同的索引。 |
hyperdrive |
按 id 绑定到 Hyperdrive 配置。必须手动创建。真正的数据隔离需要指向不同数据库或 schema 的独立配置。 |
绑定到不同的 Hyperdrive 配置。 |
analytics_engine_datasets |
写入你指定的 dataset 名称。数据集由写入隐式创建。两个 Preview 写入同一数据集时共享行。 |
绑定到不同的数据集名称。 |
pipelines |
按 pipeline ID 绑定到 Pipeline stream。两个 Preview 共享同一 stream 时会将事件发送到同一目标。 |
绑定到不同的 stream。 |
workflows |
绑定到现有 Workflow。调用使用该 Workflow 已部署的代码、绑定和实例。 | 绑定到专用的非生产 Workflow。 |
secrets_store_secrets |
按 store_id 和 secret_name 绑定到 Secrets Store 密钥。 |
绑定到不同的 store 或密钥名称。 |
dispatch_namespaces |
按 namespace 绑定到 Workers for Platforms dispatch namespace。 |
绑定到不同的 namespace。 |
mtls_certificates |
按 certificate_id 绑定到 mTLS 客户端证书。 |
绑定到不同的证书。 |
vpc_services |
按 service_id 绑定到 VPC service。 |
绑定到不同的服务。 |
ratelimits |
创建 Rate Limiting 绑定。运行时绑定名称来自 name,而不是 binding。 |
使用不同的 namespace_id。 |
send_email |
创建 Send Email 绑定。运行时绑定名称来自 name,而不是 binding。成功投递需要有效的 Email Routing 设置。 |
不适用。 |
Durable Objects 使用有状态的单例模型:在同一个 namespace 内,每个对象 ID 解析为单个实例及其存储。如果 Preview 共享 namespace,它们可能读取并覆盖相同状态。对于在同一 Worker 中定义且没有 script_name 的类,每个 Preview 会自动获得自己的 namespace 和存储。
状态会在同一 Preview 的部署之间持久化,并在 Preview 删除时删除。
| 访问模式 | Preview 配置 | 结果 |
|---|---|---|
ctx.exports |
仅类和迁移 | 推荐。每个 Preview 会自动获得独立 namespace。 |
env 绑定 |
类、迁移和 Preview 绑定 | 当你的代码需要 env.COUNTER 时使用。 |
每个 Durable Object 设置都需要从 Worker 导出 Durable Object 类,并在 Wrangler 配置中包含迁移。
使用 ctx.exports(推荐,需要 enable_ctx_exports 兼容性标志,在 compatibility_date 为 2025-11-17 或更晚时默认启用)时,仅迁移即可实现自动 Preview 隔离:
{
// Set this to today's date
"compatibility_date": "2026-11-14",
"migrations": [
{ "tag": "v1", "new_classes": ["Counter"] }
],
"previews": {}
}# Set this to today's date
compatibility_date = "2026-11-14"
previews = { }
[[migrations]]
tag = "v1"
new_classes = [ "Counter" ]生产、feature-login 和 redesign 各自获得自己的 Durable Object namespace 和存储。空的 previews 块已足够,因为不需要 Preview 专用的 Durable Object 绑定。
如果你的代码使用 env.COUNTER,请在 previews 块中声明绑定,以便 Preview 拥有它:
{
"durable_objects": {
"bindings": [
{ "name": "COUNTER", "class_name": "Counter" }
]
},
"migrations": [
{ "tag": "v1", "new_classes": ["Counter"] }
],
"previews": {
"durable_objects": {
"bindings": [
{ "name": "COUNTER", "class_name": "Counter" }
]
}
}
}[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
[[migrations]]
tag = "v1"
new_classes = [ "Counter" ]
[[previews.durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"Containers 由 Durable Objects 支持。每个 Preview 都有自己的 Durable Object namespace、container 应用和 container 实例。运行 npx wrangler preview 时,Wrangler 会为该 Preview 构建并部署镜像。生成的应用名称包含 Worker、Preview 和类名,例如 my-worker_feature-login_MyContainer。
Preview 的 container 配置不会从顶层继承。如果生产和 Preview 都需要 container,请在两处都声明:
- 顶层
containers用于生产。 previews.containers用于 Preview。
| 访问模式 | Preview 配置 | 结果 |
|---|---|---|
ctx.exports |
类、SQLite 迁移和 previews.containers |
当你的代码不需要 env 绑定时推荐。 |
env 绑定 |
类、SQLite 迁移、previews.containers 和 Preview Durable Object 绑定 |
当你的代码调用 env.MY_CONTAINER 时使用。 |
当你的 Worker 通过 ctx.exports 而不是 env 绑定访问 container 类时,使用此模式:
const container = ctx.exports.MyContainer.getByName("tenant-a");
return container.fetch(request);声明基于 SQLite 的 Durable Object 迁移和 container 配置。将 container 配置放在 previews.containers 下,以便 Wrangler 为每个 Preview 创建 container 应用:
{
// Set this to today's date
"compatibility_date": "2026-11-14",
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["MyContainer"] }
],
"containers": [
{
"class_name": "MyContainer",
"image": "./Dockerfile",
"max_instances": 10,
"instance_type": "basic"
}
],
"previews": {
"containers": [
{
"class_name": "MyContainer",
"image": "./Dockerfile",
"max_instances": 10,
"instance_type": "basic"
}
]
}
}# Set this to today's date
compatibility_date = "2026-11-14"
[[migrations]]
tag = "v1"
new_sqlite_classes = [ "MyContainer" ]
[[containers]]
class_name = "MyContainer"
image = "./Dockerfile"
max_instances = 10
instance_type = "basic"
[[previews.containers]]
class_name = "MyContainer"
image = "./Dockerfile"
max_instances = 10
instance_type = "basic"采用此设置时,生产和每个 Preview 使用独立的 Durable Object namespace 和独立的 container 应用。除非 Worker 代码从 env 读取 container namespace,否则不需要 previews.durable_objects 绑定。
如果你的代码使用 env 绑定,请在顶层为生产声明 Durable Object 绑定,并在 previews.durable_objects.bindings 下再次为 Preview 声明:
import { getContainer } from "@cloudflare/containers";
const container = getContainer(env.MY_CONTAINER, "tenant-a");
return container.fetch(request);{
// Set this to today's date
"compatibility_date": "2026-11-14",
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["MyContainer"] }
],
"containers": [
{
"class_name": "MyContainer",
"image": "./Dockerfile",
"max_instances": 10,
"instance_type": "basic"
}
],
"durable_objects": {
"bindings": [
{ "name": "MY_CONTAINER", "class_name": "MyContainer" }
]
},
"previews": {
"containers": [
{
"class_name": "MyContainer",
"image": "./Dockerfile",
"max_instances": 10,
"instance_type": "basic"
}
],
"durable_objects": {
"bindings": [
{ "name": "MY_CONTAINER", "class_name": "MyContainer" }
]
}
}
}# Set this to today's date
compatibility_date = "2026-11-14"
[[migrations]]
tag = "v1"
new_sqlite_classes = [ "MyContainer" ]
[[containers]]
class_name = "MyContainer"
image = "./Dockerfile"
max_instances = 10
instance_type = "basic"
[[durable_objects.bindings]]
name = "MY_CONTAINER"
class_name = "MyContainer"
[[previews.containers]]
class_name = "MyContainer"
image = "./Dockerfile"
max_instances = 10
instance_type = "basic"
[[previews.durable_objects.bindings]]
name = "MY_CONTAINER"
class_name = "MyContainer"使用 npx wrangler containers list 和 npx wrangler containers info <APPLICATION_ID> 检查生成的应用。Preview 中的 Container 支持是部分支持,因此在依赖它进行测试之前,请验证进程能启动并响应。
删除 Preview 会移除其 Preview 记录和 Durable Object namespace。删除传播后 Preview URL 停止提供服务,但生成的 container 应用仍可能出现在 npx wrangler containers list 中。
为确定性地清理,删除 Preview 后检查是否有残留的 container 应用:
npx wrangler preview delete --name "feature-login" --skip-confirmation
npx wrangler containers list删除属于已删除 Preview 的任何残留应用:
npx wrangler containers delete <APPLICATION_ID>你可以在 CI 中通过匹配生成的应用名前缀来自动清理。广泛使用此模式前请先审查 ID:
WORKER_NAME="my-worker"
PREVIEW_NAME="feature-login"
PREFIX="${WORKER_NAME}_${PREVIEW_NAME}_"
npx wrangler preview delete --name "$PREVIEW_NAME" --skip-confirmation
npx wrangler containers list --json \
| jq -r --arg prefix "$PREFIX" '.[] | select(.name | startswith($prefix)) | .id' \
| while read -r app_id; do
npx wrangler containers delete "$app_id"
done不要仅按 Worker 名称删除 container 应用。同一 Worker 的生产应用可能有类似名称,但不包含 Preview 名称段。
使用基础分支配置一个所有 Preview 默认共享的暂存数据库。需要隔离数据库的分支在自己的配置中覆盖该绑定。按以下步骤使每个分支的 D1 迁移 目标与其 Preview 绑定保持一致。
在基础分支上,将 Preview 绑定到 previews.d1_databases 下的共享暂存数据库。新分支会继承此配置并使用同一数据库:
{
"previews": {
"d1_databases": [
{
"binding": "DB",
"database_name": "preview-shared-db",
"database_id": "<PREVIEW_DATABASE_ID>",
},
],
},
}在基础分支上,创建名为 wrangler.preview-migrations.jsonc 的单独文件。在顶层 d1_databases 下声明共享暂存数据库。从 previews.d1_databases 复制 database_name 和 database_id:
{
"d1_databases": [
{
"binding": "PREVIEW_DB",
"database_name": "preview-shared-db",
"database_id": "<PREVIEW_DATABASE_ID>",
"migrations_dir": "migrations",
},
],
}在需要隔离数据库的分支上,同时更改两个文件中的 database_name 和 database_id:
| 文件 | 要更新的绑定 |
|---|---|
wrangler.jsonc |
previews.d1_databases |
wrangler.preview-migrations.jsonc |
顶层 d1_databases |
这两个文件必须指向同一物理数据库。其他分支继续使用基础分支中的共享暂存数据库。
将迁移文件添加到 migrations/ 目录。要使用其他位置,请更改 wrangler.preview-migrations.jsonc 中的 migrations_dir。
确认 database_name 和 database_id 与当前分支的 Preview 绑定匹配,然后应用迁移:
npx wrangler d1 migrations apply PREVIEW_DB --remote --config wrangler.preview-migrations.jsonc如果多个 Preview 共享同一 database_id,只需为该数据库运行一次迁移命令。
迁移成功后,从包含其 previews.d1_databases 绑定的分支部署 Preview:
npx wrangler preview --name feature-login这些领域的 Preview 支持可能会稍后推出。如果其中某项限制阻塞了你的工作流,请在 workers-sdk 仓库中提交 issue ↗。说明该资源应共享、按 Preview 自动创建,还是在 Preview 删除时清理。
从 Worker A 到 Worker B 的 service binding 告诉 Cloudflare:当 Worker A 调用 env.AUTH.fetch() 时,将该请求路由到 Worker B。
目前,如果 Worker A 有到 Worker B 的 service binding,并且你部署了 Worker A 的 Preview,该 Preview 只能绑定到生产 Worker B。它不会自动绑定到 Worker B 的匹配 Preview。
如果需要让同一 Worker 内的调用留在 Preview 内部,请使用 ctx.exports 而不是 service binding。
向 previews 块添加 Workflow 绑定会将 Preview 绑定到现有 Workflow。它不会创建或部署 Preview 专用 Workflow。要创建 Workflow,请使用 Wrangler 部署一个。
绑定到现有 Workflow 会运行该 Workflow 已部署的代码和绑定。其实例属于现有 Workflow。将绑定更改为新名称不会创建 Workflow。对该绑定的调用会失败,并出现 workflow.not_found。
对于隔离测试,请先部署专用的非生产 Workflow,然后将 Preview 绑定到它。绑定到同一 Workflow 的 Preview 会共享其实例。由另一个 Worker 拥有的 Workflow 会运行该 Worker 已部署的实现。
Cloudflare 正在开发按 Preview 自动预配 Workflow 的能力,类似于 Durable Objects。
Preview 可以向 Queues 生产消息。例如,如果其 previews 块包含 Queue 生产者绑定,Preview 可以调用 env.MY_QUEUE.send(message)。
目前 Preview 无法从 Queues 消费消息。一个 Queue 只能有一个消费者 Worker,而 Queues 服务尚未将 Preview 注册为该消费者。
请注意,Preview 生产到生产 Queue 的消息可能被生产消费。仅在此行为符合预期时,才将 Preview 指向生产 Queue。不要将每个 Preview 都指向一个共享暂存 Queue,并期望每个 Preview 的 queue(batch, env, ctx) 处理程序都会运行。只有一个消费者能收到这些消息。
Cron Trigger 告诉 Cloudflare:按此计划运行 Worker 的 scheduled() 处理程序。
Cron Triggers 面向生产。Preview 不会创建单独的计划调用,调度器目前也不会调用 Preview 的 scheduled() 处理程序。
要在 Preview 中测试计划逻辑,请将工作放在既可从 scheduled() 调用、也可从仅用于测试的路由调用的函数后面。然后在 Preview URL 上调用该测试路由。
生产路由 面向生产。Preview 不会接管 zone 路由、生产自定义域、Queue 消费者或其他生产触发器。
要将 HTTP 流量发送到 Preview,请使用其 workers.dev 上的 Preview URL 或自定义域 Preview URL。自定义域 Preview URL 是独立的 Preview 主机名,例如 <preview-name>.app.example.com。