Cloudflare 发布 Worker Previews:让 AI 写的每次改动,都可以直接跑在云端进行验证
给每个代码分支一个云端试验场:打开网址试功能,出了错查这次测试的日志,让人和 Agent 在合并前完成验证与修复。
Cloudflare 推出了 Worker Previews:给每个代码分支一个可以直接打开、实际操作的云端试运行版本。AI 改完代码后,你不用先把改动合进正式网站,就能打开预览网址,点一遍页面、试一遍登录;出了问题,再查看这次测试对应的日志。
它就像给每个开发分支安排一个云端试验场。网址、代码、配置和运行记录按预览分开管理,人和 Agent 都能在这里测试、修复,再决定是否合并。
这里的 Worker,是运行在 Cloudflare 边缘网络上的轻量应用,开发者不必自己管理服务器;Git 分支,则是从主线分出来、供你单独开发的一份代码。Worker Previews 让这份代码在合并之前,就有地方真正跑起来。
代码写得更快,测试不能都挤在同一个地方
开发时常见两种麻烦:“在我电脑上明明没问题,一上线就出错”;或者几个人共用一个测试环境,你改配置、我写数据,互相干扰。AI 提交代码更快以后,团队也需要更快地检查这些改动实际跑起来是什么样。
代码分支能把各自的修改分开,但如果大家最终都把代码放到同一个测试网站上,还是会抢用同一套环境。另一方面,本地用模拟服务做测试,也不一定能重现真正的云端请求、登录授权和异步任务。
有了各自的预览环境,每个人就能先打开自己的版本,试功能、查错误、修改后再测。Cloudflare 将这种让 Agent 参与测试、排错和修订的研发流程称为 Agent Development Lifecycle(ADLC)。
如上图所示,有了隔离的预览环境并配置 Workers Builds 后,推送分支即可让改动在云端运行。测试失败,就根据报错修改代码,再部署一次;确认表现符合预期后,团队再决定是否合并到生产主线。
每个分支一个预览网址,改完就能打开试
在代码分支上运行 npx wrangler preview,就能创建对应的云端预览,并拿到一个独立网址。后续更新这个分支,仍使用同一个网址;发给同事的评审链接不用每次重发。配置 Workers Builds 后,推送分支还可以自动更新预览。
同一个 Worker 之下,可以并行运行数百个预览环境。 你可以同时检查修按钮的版本、加功能的版本和改数据库的版本,在同一个控制台里切换查看。
旧版 Wrangler environments 需要为不同环境分别部署和管理 Worker;旧预览 URL,如今改称 Version URLs,则指向某个上传版本,仍可能访问生产资源。Worker Previews 把按分支管理的运行环境集中到同一个 Worker 下。
从上图可以看出,在同一个 my-worker 项目里:
- 生产环境(Production):跑着主分支代码,绑定生产数据库(如
D1:prod,D1 是 Cloudflare 的数据库)。 - 常规特性分支(如 fix-button, new-feature):自动继承预览配置,统一指向测试库(
D1:staging),甚至可以根据需求追加分支专用的对象存储(R2:feature-assets)。 - 破坏性变更分支(如 d1-migration):为了测试破坏性表结构变更,可以单独覆盖配置,将其重定向到专属的临时测试库(
D1:migration-test),把这次数据库迁移的影响限制在所选测试库里。
配置副本并不等于数据库副本:从图中可以看出,fix-button 和 new-feature 两个分支在配置中共同指向了同一个 D1:staging 测试库,只有破坏性变更分支独立指向了 D1:migration-test;这意味着连接到同一测试库的分支之间,仍可能因为并发写入而产生相互影响。这类存储绑定完全由开发者按需选择配置,这些绑定不会自动变成每个分支专属的 D1 数据库、R2 存储桶或 KV 存储副本。
在 Cloudflare 控制台(Dashboard)中,这种操作被设计得像切换 Git 分支一样直观:
开发者或评审人员只需在顶部下拉菜单里选择对应分支(如 new-feature、d1-migration、fix-button),就能立即调出该分支专属的监控、绑定资源和运行状态。这样,评审时可以把运行版本、配置和日志对应起来。
测试也有自己的状态,避免碰到正在使用的数据
如果应用会记住会话、计数或操作记录,测试时就不只是在试一份代码,还可能在修改它保存的数据。这些需要被应用记住的信息,就是状态。
Worker Previews 会为每个预览准备独立的 Durable Objects(持久化对象,简称 DO)状态空间与容器应用。这样,按下面的方式访问 DO 时,测试版本找到的是自己的对象,而不是生产环境里正在服务真实用户的那个对象。
为什么只分开代码还不够
Durable Objects 通过对象 ID 找到对应对象。在同一个命名空间里,用同一个 ID 找到的是同一个对象及其存储,这就是它的全局单例模型(Singleton Model)。
如果预览和生产共用这个命名空间,即使运行的是两份代码,也可能找到同一个对象。你在预览中写入测试数据,就可能改到真实用户正在使用的数据。
给预览单独分配一套对象空间
现在,只要执行 npx wrangler preview,Cloudflare 底层就会自动为该分支按需生成一个独立的 Durable Object 命名空间与容器应用(Container application)。
开发者无需在代码中手写复杂的“环境判断逻辑”,导出对应类、添加它的迁移配置,再通过 ctx.exports 访问。下面是原文的机制片段;实际使用还需从 cloudflare:workers 显式导入 DurableObject 基类、在类内部实现具体的业务处理逻辑,并在配置文件中完成迁移配置:
export class Counter extends DurableObject {}
export default {
async fetch(request, env, ctx) {
// 关键点:通过 ctx.exports 引用 Counter
const id = ctx.exports.Counter.idFromName("demo");
const counter = ctx.exports.Counter.get(id);
return counter.fetch(request);
},
};
相同代码如何找到不同的状态:
- 当这段代码运行在生产环境时,
ctx.exports.Counter会自动解析为生产环境的 Durable Object 命名空间。 - 当同一段代码运行在预览分支时,系统会透明地将其重定向解析到该分支专用的预览命名空间。
有了各自的运行状态,做沙箱冷启动优化的工程师,可以把不同配置放到不同分支上,同时比较首次启动和已运行过后的响应表现。
D1、R2、KV 仍要看实际连到了哪里。 上一节图中的两个常规分支都指向同一个 D1 测试库,写入的数据仍会互相影响。要做改表结构等破坏性测试,就应像迁移分支那样,显式指定专属测试资源。
常用测试设置配一次,特殊分支单独改
不用每开一个分支,就重新填一遍测试变量、密钥和资源地址。先配好一套通用测试设置,新预览从这套设置开始;哪个分支有特殊需要,再只改它自己的配置。
Worker Previews 引入了 Base Configuration(基础配置) 的概念。你只需要在 Wrangler 配置文件(wrangler.json 或 wrangler.toml)中显式声明一次 previews 代码块:
{
"vars": {
"ENVIRONMENT": "production"
},
"r2_buckets": [
{
"binding": "UPLOADS",
"bucket_name": "prod-uploads"
}
],
"previews": {
"vars": {
"ENVIRONMENT": "preview"
},
"r2_buckets": [
{
"binding": "UPLOADS",
"bucket_name": "r2-staging"
}
]
}
}
在上面的配置中:
- 顶层配置属于正式生产环境,使用的是
prod-uploads存储桶; - 嵌套在
previews块下的内容就是所有预览分支的“公共底座”,默认将变量切换为preview,并把文件上传导向测试专用的r2-staging存储桶。
在控制台的 Settings 界面中,你可以清楚地看到生产环境配置与预览基准配置并排排列:
如果某个特殊分支有独特需求呢?例如一个名为 add-new-websiter-counter 的分支正在开发新计数器,需要挂载额外的测试 KV 键值存储,你完全可以针对这单一分支执行配置覆盖(Override):
这样,常规分支沿用已有测试设置,特殊分支可以改用自己的存储或密钥;修改这个预览的配置,不会顺带修改生产、基础配置或其他预览的配置。
出了错,只看这次预览的运行记录
你在预览网页上点了一次按钮,后台到底有没有收到请求、哪一步失败,可以到这个预览自己的监控页面里查。不用把本次测试和正式网站、其他分支的日志混在一起找。
这些工具统称为 Workers Observability,可以查看日志、错误、性能指标和调用追踪。调用追踪会把一次请求经过的处理步骤串起来,帮助你找到出问题的位置:
Agent 可以自己打开网页、查日志,再修改代码
把这些工具接给 Agent,就可以串起一条测试流程:写代码 → 部署预览 → 打开网页操作 → 查日志 → 修改 → 再测。
浏览器工具负责看页面发生了什么,日志工具负责看后台发生了什么。通过 MCP(模型上下文协议,让 Agent 调用这些外部工具的接口),Agent 可以把两边的信息对应起来:
- 部署后,自己打开网页操作:连接 Workers Builds 后,推送分支可以自动部署;也可以运行
npx wrangler preview。同一分支后续推送更新同一稳定 URL。Agent 通过 Playwright MCP 调用 Cloudflare Browser Run(云端无头浏览器),自动在后台打开该 URL,一步一步执行注册、登录、点击等操作,并实时截屏或录制 DOM 事件。 - 操作失败,再查后台发生了什么:一旦某个操作失败(例如按钮点了没反应),Agent 可以直接调用 Workers Observability MCP Server,查询相关事件和调用追踪,查看请求中的 fetch、资源绑定操作与处理函数调用。
这张演示图说明了为什么“页面能打开”还不够。前端页面(Region: Earth)已经显示出来,后台却出现了异常:后台端点返回 500(GET /api/observability/scenario?case=6),并伴随容量规则失败事件(preview_capacity_rule_failed)。图中还直接揭示了用户影响——该区域用户可能无法正常打开 Dashboard 入口按钮;同时给出了用于关联排查的 debug 标识 pr-5-wobs-15min-1788388576(可搭配 $metadata.error Exists 过滤查询)。有了这些线索,Agent 或开发者就能继续排查,并在合并前重新验证 Dashboard 入口路由。
需要人类判断时,评审人员可以通过 Live View 实时查看浏览器操作,或用 Human in the Loop 介入。
登录流程也能实际测试,预览网址还能加访问限制
一个页面能打开,不代表用 Google 或 GitHub 登录也能顺利完成。登录还涉及第三方服务把用户送回哪个网址、Cookie 在哪些域名下生效,以及浏览器是否允许跨域请求。
Worker Previews 支持把预览放在自己的域名下。例如正式网站是 example.com,登录功能的测试版本可以用 feature-login.previews.example.com,让团队实际走一遍更接近正式部署的登录与授权流程:
使用自定义域名后,团队仍需把第三方登录的 OAuth 回调地址配成对应的预览网址,并让 Cookie 作用域与跨域资源共享(CORS)策略匹配。
不想让外部访问未上线的版本,还可以给预览网址加一道访问限制。 配置 Cloudflare Access 后,访问者需要先登录,再按你设置的访问规则放行。
CloudflareOS 为什么要连着权限系统一起测
Cloudflare 官方在推出该功能前,已经用它开发和测试内部开源项目 CloudflareOS。 CloudflareOS 的核心职责是安全地把 AI Agent 连接到企业内部的 Google、GitHub、Slack 等生产系统,其中最关键的模块叫做 Gatekeepers(看门人鉴权层),用来严格限制 Agent 能调用的权限范围。
看门人模块的代码极其敏感:一个微小的逻辑漏洞,就可能导致 Agent 越权访问公司核心机密数据。而且,这类涉及多方 OAuth 授权跳回、权限审批流和应用实时状态的复合逻辑,仅测试各个组件无法展示完整系统的行为。 Cloudflare 团队的做法正是:每次针对 Gatekeeper 提出修改,都会拉起一个独立的 Worker Preview,完整运行审批鉴权流程,修复失败之处并重新测试,再合并。
原文还引用了两位使用者的反馈:
- Supermemory 创始人 Dhravya Shah 表示,他们使用 Worker Previews 来测试包含 Durable Objects 调用的 HTTP 流,无需放慢迭代节奏就能在更早阶段拦截异常。
- Ramp 高级工程师 Dylan Garcia 则分享,由于预览环境随时随地都在线,他甚至可以直接在手机上通过移动端查看并验证由其 Agent(Inspect)生成的 PR 预览效果。
哪些调用还没有自动留在预览环境里
Worker Previews 还没有自动覆盖所有资源与调用路径。目前官方披露的已知限制与规划包括:
- 跨 Worker 调用(Service Bindings)尚未完全隔离:
- 当前现状:如果当前预览分支中的 Worker 通过 Service Binding 调用了系统里的另一个关联 Worker,这个请求默认仍然会打到目标 Worker 的生产部署上。
- 演进方向:Cloudflare 正在开发匹配预览之间的路由,使整个调用链都能停留在相互匹配的预览环境中。
- 异步队列与工作流的消费隔离:
- 当前现状:预览环境目前支持向 Queues(队列)发送消息,但不能消费消息;同时隔离 Workflows 的执行需要单独配置。
- 演进方向:正努力将包括消息队列、异步工作流在内的整套异步链路完全收敛在分支作用域内。
- 支持长期存在的环境(Long-lived Previews):
- 针对需要持续数个开发迭代周期、跨周期维护的固定 Staging 或 QA 环境,Cloudflare 正在设计面向长期使用的预览支持方案。
Cloudflare 发布 Worker Previews:让 AI 写的每次改动,都可以直接跑在云端进行验证
Worker 是运行在 Cloudflare 边缘网络上的轻量应用。代码分支能把改动分开,但共用测试环境时,配置与数据仍可能互相干扰;本地模拟测试也无法完整复现云端行为。
一个 Worker,多个可运行的分支
每个预览有独立 URL、配置与监控。通过 previews 配置统一的测试设置,特殊分支再单独覆盖。下图是存储绑定示例:
状态隔离,要分清两类资源
Durable Objects(DO)负责保存会话、计数等状态。同一命名空间内,相同对象 ID 会对应同一对象。预览会按需派生独立的 DO 命名空间与容器应用;导出类并配置迁移后,通过 ctx.exports 访问,就会解析到当前环境的命名空间。
配置副本 ≠ 数据库副本。上图常规分支仍共用 D1 测试库。D1、R2、KV 不会自动克隆;数据库迁移等破坏性测试,应显式绑定专属测试资源。
Agent 如何从页面追到后台
稳定 URL 让 Agent 反复测试同一分支;对应的日志与调用追踪,帮助把页面问题关联到后台请求。
合并前,还要核对这些连接
CloudflareOS 用预览完整测试 Gatekeepers 权限审批流程。自定义域名与 Cloudflare Access 可帮助搭建测试入口,但 OAuth 回调、Cookie 作用域与 CORS 仍需正确配置。
Introducing Worker Previews: isolated preview environments for every change your agent makes
Worker Previews gives every branch its own URL, configuration, state, and observability, so you and your agents can test changes in parallel without affecting production.
Nothing is worse than testing out a change that works in staging, only to see it behave differently in production. That’s why we wanted to give you an environment that’s as close to production as possible — so you can battle-test your changes and make sure they behave exactly as you expect them to.
Agents are helping us push more lines of code than ever before, and larger changes mean more ground needs to be tested ahead of release. Ideally, that testing is done in a way that doesn’t slow agents down, but gives them the tools to take on more of the development lifecycle.
That’s why today we’re launching Worker Previews. Each Git branch gets a production-like place to run, with its own code, configuration, URL, observability, and state.
So now, for every change in your codebase, you can:
- Deploy an isolated Preview with
npx wrangler preview, using its own variables, secrets, and bindings, separate from production configuration and traffic. - Share a stable Preview URL for the branch so that every push updates the same running Preview where you can send requests, click through the UI, and test runtime responses.
- Isolate Durable Objects and Containers per branch, keeping state changes, sessions, memory, migrations, and concurrent tests scoped to that Preview.
- Inspect logs, errors, metrics, and traces for that Preview to confirm the change works, catch failures, push a fix, and verify it before production sees it.
- Start from the Preview configuration you set, so each Preview begins with a copy of the variables, secrets, bindings, and settings you define — just like a code branch starts from
main. We call this the base configuration. - Override a Preview’s configuration when needed, like pointing it at its own database or test API key for migrations — without changing production, the base, or other Previews’ configuration.
- Serve Preview URLs on a custom domain so that auth providers, cookies, cross-origin resource sharing (CORS), and OAuth redirects work the same way they will in production.
The result is a pre-production feedback loop for every branch. Push your change to a branch, test behavior, inspect performance — before you merge to production.
This enables an Agent Development Lifecycle (ADLC) where each change is atomic, independently deployable, observable, and revisable. And it gives agents and humans the evidence they need to self-improve: catch what failed, push a fix, and verify the next deployment before it hits production.
Every Git branch gets its own environment
When you start work on a new feature, the first thing you do is branch off of main. You get your own copy of the code and make your changes without affecting anything in production.
Worker Previews extend that same model beyond code. Each branch gets its own isolated environment and URL. You can run hundreds of Previews at the same time — each operating independently without affecting other Previews or production.

Production and each Preview have their own configuration — served on their own URL.
When you run npx wrangler preview, the branch gets its own copy of your Previews configuration that you have defined, running on its own URL — all under the same Worker.
In the dashboard, this works like switching branches. Click the breadcrumb next to your Worker's name (it defaults to Production) to see all your Previews:
The dashboard brings every environment into one view. Production sits alongside as many Previews as you need, so contributors can work on separate changes without fighting over a shared staging site. Unlike Wrangler environments, where each environment requires deploying and managing a separate Worker, Previews keep that isolation in one dashboard view.
Each Preview runs as a real version of your Worker. Some changes can only be validated at runtime: an API endpoint has to handle a real request and return the right response. More subjective changes, like a UI update, a new onboarding step, or a different error state, need to be experienced in context before they reach production.
Every Preview has its own isolated and persistent state, with Durable Objects and Containers
For isolation to extend across your application, stateful resources need special treatment. The reason for that is that Durable Objects run on a singleton model. One instance is responsible for a given object ID, and that instance owns its storage.
If a Preview shared the same DO namespace as production, you wouldn't just be reading stale data — you could modify the same instance serving live traffic in real time (scary!).
That is why every time you run npx wrangler preview, Cloudflare automatically creates a new Durable Object namespace and Container application for that Preview — so that a failed migration or a bad schema change stays contained to that branch and that branch only.
All you need to do is export the class, add its migration, and access it through ctx.exports:
export class Counter extends DurableObject {}
export default {
async fetch(request, env, ctx) {
const id = ctx.exports.Counter.idFromName("demo");
const counter = ctx.exports.Counter.get(id);
return counter.fetch(request);
},
};In production, ctx.exports.Counter resolves to the production namespace, while in a Preview, it resolves to that Preview’s namespace.
You now have an entire playground to experiment with. Take Sandboxes, for example, where milliseconds of improvement to startup time can make or break the experience. If you have been trying to improve cold-start performance, you can run different configurations across branches at the same time, compare their cold and warm performance side by side, and find the best setup faster.
Test, observe, and revise each Preview (or have your agent do it)
Now that each branch runs at its own URL in an isolated environment with its own state, you can enter the feedback loop and start battle-testing every change before it reaches production.
You can send traffic to the Preview URL however you normally would — from your terminal, probe from CI, an agent, or by clicking through it yourself. Once that traffic starts flowing, every Workers Observability tool you’re already used to is available, scoped to each individual Preview.
As each request hits the Preview, Workers Observability traces its full lifecycle in a waterfall, including fetch calls, binding operations, and handler invocations. So when something fails, you can follow exactly what happened without sorting through production traffic or signals from other changes.
Observability for Previews looks just like you're already used to for production Workers. Select your Preview from the breadcrumb and open the Observability tab to see its events, errors, and traces:
To give your agents even more control, you can have them open the Preview URL in a headless browser, click through a login flow step by step, and capture a screenshot or record the entire session as replayable DOM events – with Browser Run.
Below is an example where an agent opens the Preview, captures what was rendered, and connects a failed request to Workers Observability events from the same run.
A reviewer can watch the session in real time withLive View or step in withHuman in the Loop when the automation needs judgment.
If something fails, you see it from both angles: what rendered and what happened at runtime.
That gives the agent enough evidence to keep the pre-production loop running autonomously: deploy, open the URL withPlaywright MCP, click through, query the traces through theWorkers Observability MCP server, patch, redeploy, and verify. Every iteration stays scoped to the branch.
Configure a base configuration for Previews once, then override as needed
Just like you wouldn't reconfigure your code from scratch every time you branch, you shouldn't have to reconfigure your environment either.
You set base configuration for Previews once, in a previews block in your Wrangler configuration file.
{
"vars": {
"ENVIRONMENT": "production"
},
"r2_buckets": [
{
"binding": "UPLOADS",
"bucket_name": "prod-uploads"
}
],
"previews": {
"vars": {
"ENVIRONMENT": "preview"
},
"r2_buckets": [
{
"binding": "UPLOADS",
"bucket_name": "r2-staging"
}
]
}
}In the dashboard under Worker → Settings, you see this inlined as Production and Previews Base. Once the base is set, run npx wrangler preview from any branch to create a Preview. If your Worker is Git-connected through Workers Builds, it happens automatically on push.
You can override any setting for only one Preview — without affecting production, the base, or other Previews.
Preview URLs on your own custom domain, protected with Cloudflare Access
To bring the whole setup even closer to production, your preview URLs can be served from your own custom domain. If your app runs on example.com, a Preview for a login branch could run at feature-login.previews.example.com.
If you want to keep those URLs private, you can protect your Previews with Cloudflare Access and require visitors to sign in first.
Testing the whole system before production
We’ve already been dogfooding Worker Previews inside Cloudflare, most notably to build and testCloudflareOS, our open-source platform for safely connecting agents to company systems.
CloudflareOS lets agents work with services such as Google, GitHub, and Slack throughGatekeepers, which control what those agents can access and change. That makes Gatekeeper changes especially sensitive, because a bug could expose data or permit an action that should never have been allowed.
Some of these bugs only appear when OAuth callbacks, permissions, approval flows, and application state are running together. Because testing each component separately cannot show us how the complete system will behave, we deploy an isolated Preview of CloudflareOS and its Gatekeepers for every change under review. We then run the full workflow, fix what fails, and test it again before merging.
We’re seeing customers use Previews for the same basic reason: some problems only show themselves when the change is actually running.
"At Supermemory, we use Cloudflare heavily, and Worker Previews are exactly the kind of developer experience improvement we wanted to see. For HTTP flows, we can preview Worker changes before they reach production, including routes backed by Durable Objects, and catch issues earlier without slowing down shipping." — Dhravya Shah, Founder, Supermemory
"Previews is amazing for Inspect [Ramp’s coding agent]. I used it to review and test an Inspect PR on my phone that is making reviewing and testing PRs with Inspect on phones responsive…with Inspect." — Dylan Garcia, Senior Staff Engineer, Ramp
What’s next?
You might be thinking: Didn't Workers already have preview URLs? It’s true, we did. We're now calling thoseVersion URLs because they point to specific uploaded Worker versions. Unlike Worker Previews, they don't create an isolated environment for each branch and could only point to production resources. To learn more and compare the different workflows, check out our docs.
Worker Previews is a big improvement from what we offered before, but there's still more to come. Here's what we're working on next:
- Preview multi-Worker applications. Today, a service binding from a Preview still calls the bound Worker's production deployment. We're working toward keeping the entire request path inside matching Previews.
- Run Queue consumers and Workflows inside each Preview. Today, Previews can send messages to Queues but cannot consume them, while isolating Workflow executions requires separate configuration. We want the entire asynchronous flow scoped to the branch automatically.
- Support long-lived Previews for staging and QA. We've heard from teams in the private beta that not every branch is short-lived — some maintain staging, QA, or per-developer environments that persist across sprints. We want to support these end-to-end, and we want to hear how you use them, so we can get it right.
Worker Previews are available now. Get started with the docs, and if you have a feature request or run into an issue, open an issue on GitHub or join the Cloudflare Developers community on Discord.
Acknowledgements: This project was made possible by the design and implementation efforts of Greg Brimble, Patrick O’Donnell, Matt Price, Korinne Alpers, Max Peterson, Cina Saffary, Josh Wheeler, Thomas Ankcorn, Matt Rothenberg, and Brandon Strittmatter, with leadership from Brendan Irvine-Broque and Dan Carter.
