Skip to content

Changelog

New updates and improvements at Cloudflare.

Workers
hero image
  1. Platforms can now create temporary preview accounts through the Cloudflare REST API. This lets your platform deploy a live Worker before the user signs in to Cloudflare.

    With the Temporary Accounts API, coding agents, AI app builders, and other platforms can build a similar flow for generated Workers and supported resources.

    Your platform can keep users in its onboarding flow while they generate, deploy, and test an application. Users do not need an existing Cloudflare account, and your platform does not need write access to one.

    Diagram showing an AI agent deploying, verifying, and redeploying a Worker in a temporary account, then a user authenticating and claiming the account to keep its resources

    The API returns a claim URL that lets the user make the temporary account and its resources permanent.

    Cloudflare Drop demonstrates this preview-and-claim pattern for static sites. Someone can upload a site, test and share it for one hour, then sign in or create an account only when they want to keep it.

    This API expands the flow first introduced with wrangler deploy --temporary. Your backend now controls the provisioning and deployment experience directly:

    1. Show Cloudflare's Terms of Service and Privacy Policy in your product, and require the user to accept them.
    2. Request and solve a proof-of-work challenge.
    3. Create a temporary preview account.
    4. Deploy with the returned temporary account ID and API token.
    5. Show the deployed Worker URL and claim URL to the user.
    Terminal window
    curl "https://api.cloudflare.com/client/v4/provisioning/previews/challenge" \
    -X POST \
    -H "Content-Type: application/json" \
    --data '{}'
    curl "https://api.cloudflare.com/client/v4/provisioning/previews" \
    -X POST \
    -H "Content-Type: application/json" \
    --data '{
    "termsOfService": "https://www.cloudflare.com/terms/",
    "privacyPolicy": "https://www.cloudflare.com/privacypolicy/",
    "acceptTermsOfService": "yes",
    "challengeToken": "<CHALLENGE_TOKEN>",
    "solution": {
    "checkpoints": "<BASE64_CHECKPOINTS>"
    }
    }'

    For the complete API flow, proof-of-work requirements, supported products, and limits, refer to Claim deployments (temporary accounts). For the background and design goals behind this flow, refer to Temporary Cloudflare Accounts for AI agents.

  1. Agents connected to Model Context Protocol (MCP) servers with addMcpServer can now handle elicitation requests.

    Elicitation lets an MCP server request user input while it handles a tool call. Form mode collects structured, non-sensitive data. URL mode asks for consent before opening an out-of-band flow, such as third-party authorization or payment.

    sequenceDiagram
        participant User
        participant Agent as Agent (MCP client)
        participant Server as MCP server
        participant Browser
    
        Server->>Agent: elicitation/create
        Agent->>User: Show server, reason, and input or URL
        User->>Agent: Submit, open, decline, or cancel
        Agent->>Browser: Open URL after consent (URL mode)
        Agent->>Server: accept, decline, or cancel
        Server-->>Agent: Optional URL completion notification
    

    Register a handler for each mode your Agent supports in onStart():

    JavaScript
    import { Agent } from "agents";
    export class MyAgent extends Agent {
    onStart() {
    this.mcp.configureElicitationHandlers({
    form: (request, serverId) => this.forwardToUser(request, serverId),
    url: (request, serverId) => this.forwardToUser(request, serverId),
    });
    }
    forwardToUser(request, serverId) {
    // Show the request in your UI and resolve after the user responds.
    throw new Error(
    `Implement elicitation for ${serverId}: ${request.params.message}`,
    );
    }
    }

    Connections advertise only the modes with configured handlers. An Agent without handlers advertises no elicitation capability, which lets the server use its fallback. The SDK stores the advertised modes with each MCP server registration so they survive Durable Object hibernation. Callback functions remain in memory and reattach when onStart() runs.

    For implementation details and a browser forwarding pattern, refer to MCP client elicitation. The mcp-client and mcp-elicitation examples implement both sides.

    Upgrade

    To update to this release:

    npm i agents@latest
  1. If your account does not already have a key-value (KV) backed Durable Object namespace, you can no longer create new ones. New Durable Object namespaces must use the SQLite storage backend, which has been recommended for all new Durable Objects since it became generally available in 2024.

    Create a new class with a new_sqlite_classes migration:

    JSONC
    {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "migrations": [
    {
    "tag": "v1",
    "new_sqlite_classes": [
    "MyDurableObject"
    ]
    }
    ]
    }

    SQLite-backed Durable Objects have feature parity with the key-value backend — including the key-value storage API — and additionally support relational SQL queries and point-in-time recovery to restore an object's storage to any point in the past 30 days.

    If you attempt to create a new key-value backed namespace (a new_classes migration) on an affected account, the deployment fails with the following error:

    Creating new key-value backed Durable Object namespaces is no longer supported on this account. Please create a namespace using a `new_sqlite_classes` migration instead.

    This change only affects accounts that are not already using the key-value storage backend. Accounts with at least one existing key-value backed namespace can still create new ones for now, and the Workers Free plan has only ever supported SQLite-backed Durable Objects. It is part of a broader move toward SQLite as the single storage backend for Durable Objects, ahead of a future migration path for existing key-value backed objects.

    For more information, refer to Durable Objects migrations.

  1. Wrangler now collects npm package dependency information from your project's package.json during wrangler deploy and wrangler versions upload, and includes it in the upload metadata sent to the Cloudflare API. This data, each dependency's name, declared version range, and exact installed version, enables dependency analytics and future supply chain security features such as vulnerability alerting.

    To opt out, set dependencies_instrumentation.enabled to false in your Wrangler configuration file:

    JSONC
    {
    "dependencies_instrumentation": {
    "enabled": false
    }
    }

    For more details, refer to Wrangler configuration.

  1. Cloudflare Drop lets you deploy a static site to Cloudflare without requiring a Cloudflare account to get started.

    Cloudflare Drag and Drop upload screen for browsing folders or ZIP files

    Upload a folder or zip file of static assets (static HTML, CSS, JavaScript, images, and fonts) and get a temporary live preview that stays live for 1 hour. During that window, you can test the site, share the preview URL, or claim the deployment to keep it.

    Cloudflare Drag and Drop temporary live preview screen with claim and copy claim link actions

    When you are ready to make the deployment permanent, click Claim to sign in or create a Cloudflare account. You can claim the site into an existing Cloudflare account or create a new account for the deployment.

    Cloudflare Drag and Drop claim account screen with a countdown before the claim link expires

    After claiming the site, you can:

    • Add a domain: Connect an existing domain or purchase a new one for your site.
    • Enable observability: Monitor your site's performance and usage.
    • Enable Markdown for Agents: Allow AI agents to access your site's content in Markdown.
    • Control access: Make your site private and choose who can view it.
    Claimed Cloudflare Drag and Drop site setup screen showing options to add a domain, control access, enable observability, and enable Markdown for agents
  1. A new declarative exports field in your Wrangler configuration file replaces the imperative migrations array for managing Durable Object class lifecycle. Instead of writing an ordered list of migration steps with unique tags, you declare each Durable Object class your Worker exports and Cloudflare compares that against what's already deployed to determine what Durable Object state needs to be created, renamed, or deleted.

    With legacy migrations, renaming ChatRoom to Room requires retaining both tagged steps:

    Before — legacy migrations
    {
    "migrations": [
    { "tag": "v1", "new_sqlite_classes": ["ChatRoom"] },
    {
    "tag": "v2",
    "renamed_classes": [{ "from": "ChatRoom", "to": "Room" }],
    },
    ],
    }

    With exports, you instead declare Room as the current class and mark ChatRoom as renamed:

    After — declarative exports
    {
    "exports": {
    "ChatRoom": {
    "type": "durable-object",
    "state": "renamed",
    "renamed_to": "Room",
    },
    "Room": { "type": "durable-object", "storage": "sqlite" },
    },
    }

    Each entry is keyed by class name. The state field carries the lifecycle (created by default — a live class — plus tombstone states deleted, renamed, and transferred, and the expecting-transfer receiving state for cross-Worker transfers).

    Key improvements over the legacy migrations array:

    • No migration tags. The current exports map is the source of truth — there is no historical chain of v1, v2, v3 entries to maintain.
    • Structured deployment output. Wrangler reports when it creates, updates, deletes, renames, or transfers Durable Object classes. It also identifies stale configuration entries that are safe to remove. Deployments with no changes or notices do not print this output.
    • Zero-downtime rename and transfer patterns are first-class. Tombstones may coexist with the source class still in code, enabling a three-deploy rename and a four-deploy cross-Worker transfer without runtime errors during the rollout window.
    • Cross-Worker safety. When you delete or rename a class, Cloudflare lists every other Worker in your account whose bindings still reference the namespace, so you can redeploy them before the change goes live.

    Existing Workers using the legacy migrations array continue to work unchanged. To move to exports, refer to the migration guide. exports and migrations are mutually exclusive within a single Worker.

    For the full reference, refer to Durable Object class exports.

  1. We have released version 5 of @cloudflare/workers-types. This release simplifies the package to expose only the latest runtime types.

    We still recommend that you generate types for your Worker using wrangler types, but if you want to use the package directly, you can install it with your package manager of choice:

    npm i -D @cloudflare/workers-types@latest

    The package now exposes two entrypoints:

    • @cloudflare/workers-types reflects the latest compatibility date, using the latest stable compatibility flags.
    • @cloudflare/workers-types/experimental reflects APIs behind experimental compatibility flags.

    The dated entrypoints, such as @cloudflare/workers-types/2022-11-30 and @cloudflare/workers-types/2023-03-01, are removed. With runtime type generation in Wrangler v4, you can generate these with the wrangler types command to create types locked to your Worker's compatibility date.

    For more information, refer to TypeScript language support.

  1. Wrangler CLI now supports auth profiles: named logins that you scope to specific Cloudflare accounts and switch between automatically, based on the directory you are working in.

    A profile is a named OAuth login bound to a directory. Commands run in that directory, and its subdirectories, use the matching account — so you can move between accounts without re-running wrangler login.

    Use profiles to keep a separate login for each client when working at an agency, or to separate staging and production into different accounts. Pair a profile with an account_id in your Wrangler configuration file so a command cannot reach the wrong account.

    Terminal window
    # Create a profile for each account, choosing which accounts it can reach
    wrangler auth create client-a
    wrangler auth activate client-a ~/clients/client-a
    wrangler auth create client-b
    wrangler auth activate client-b ~/clients/client-b

    Use the --profile flag to run a single command with a specific profile:

    Terminal window
    wrangler deploy --profile personal

    In CI and other automated environments, CLOUDFLARE_API_TOKEN still takes precedence over all profiles.

    For setup, the resolution order, and the full command reference, refer to Authentication profiles.

  1. You can now monitor how much memory your Workers and Durable Objects consume across invocations with the new Memory Usage chart in the Workers Metrics tab, broken down by P50, P90, P99, and P999 percentiles.

    Memory usage chart showing P50, P90, P99, and P999 percentiles with deployment markers

    Memory usage measures the V8 isolate memory at the time of each invocation, subject to the 128 MB per-isolate limit — a single isolate can handle many concurrent requests and shares memory across them.

    Use the Memory Usage chart to:

    • Track memory trends — Spot gradual increases that may indicate a memory leak before they cause Exceeded Memory errors.
    • Correlate with deployments — Deployment markers on the chart help you identify whether a new version introduced a memory regression.
    • Right-size your Worker — Understand your baseline memory footprint and how much headroom you have before hitting the 128 MB limit.

    For Durable Objects, memory usage reflects the in-memory state an object holds (class properties, caches, active WebSocket connections), which persists across invocations until the object is hibernated or evicted. This state is not preserved across eviction, hibernation, or a crash, so persist anything important to storage.

    To view memory usage, open the Metrics tab for your Worker or Durable Object namespace. For Durable Objects, you can filter by DO ID or name to drill down into memory usage for a specific object. You can also query memory usage programmatically via the GraphQL Analytics API using the workersInvocationsAdaptive dataset — the quantiles.memoryUsageBytesP50 through quantiles.memoryUsageBytesP999 fields return percentile values in bytes.

    For local memory debugging, you can also profile memory with DevTools to take heap snapshots and identify specific objects causing high memory usage.

  1. Workers fetch() requests now support the cf.vary request option. Use cf.vary to control how Cloudflare caches origin responses with a Vary header for a single subrequest.

    src/index.js
    export default {
    async fetch(request) {
    return fetch(request, {
    cf: {
    vary: {
    default: { action: "bypass" },
    headers: {
    accept: {
    action: "normalize",
    media_types: ["text/html", "application/json"],
    },
    "accept-language": {
    action: "normalize",
    languages: ["en", "fr", "de"],
    },
    },
    },
    },
    });
    },
    };

    For more information, refer to cf.vary.

  1. The latest release of the Agents SDK makes it easier to run long work in the background, drive turns through one entry point, and keep chat agents working through deploys, evictions, and reconnects.

    This release adds first-class detached (background) sub-agent runs with live progress and durable milestones, a single runTurn turn-admission entry point, and a large round of recovery and reliability fixes that continue converging @cloudflare/think and @cloudflare/ai-chat onto one model.

    Background sub-agents with progress and milestones

    runAgentTool can now dispatch a sub-agent without blocking the calling turn. A detached run returns a handle immediately and is owned by a durable, eviction-surviving backbone instead of being abandoned when the dispatching turn ends.

    JavaScript
    class OrdersAgent extends Think {
    async startImport(input) {
    // Fire-and-forget, or wire a durable completion callback
    // (by method name, like schedule()):
    await this.runAgentTool(ImportAgent, {
    input,
    detached: { onFinish: "onImportDone", maxBudgetMs: 60 * 60 * 1000 },
    });
    }
    // result.status: "completed" | "error" | "aborted" | "interrupted"
    async onImportDone(run, result) {}
    }

    Highlights:

    • Durable, exactly-once-on-the-happy-path completion via a warm fast path plus a self-scheduling reconcile backbone that survives eviction and deploys.
    • Bounded. An absolute maxBudgetMs ceiling (default 24h) and cancelAgentTool(runId) keep abandoned runs from holding a concurrency slot forever.
    • detached: { notify: true } lets a finished background run inject a message back into the chat so the model reacts to the result — no hand-wired onFinish needed.

    Sub-agents can also report mid-run progress that rides their own turn stream back to the parent's connected clients:

    JavaScript
    // Inside the child sub-agent:
    await this.reportProgress({
    fraction: 0.6,
    phase: "deploying",
    message: "Generating menu page…",
    });

    Progress surfaces on AgentToolRunState.progress via useAgentToolEvents, so a background-runs tray can render a live bar without drilling in, and the latest snapshot is persisted for inspection after eviction. Naming a milestone promotes a signal to a durable, replayable row, and detached: { onMilestones } can surface a milestone as a synthetic chat message ("narrate" for a cheap status line, or "react" to drive a model turn).

    One entry point for turns: runTurn

    @cloudflare/think adds a public runTurn(options) facade that unifies turn admission behind a single mode:

    JavaScript
    await this.runTurn({ mode: "wait", messages }); // saveMessages / continueLastTurn
    await this.runTurn({ mode: "submit", messages }); // durable submitMessages
    await this.runTurn({ mode: "stream", messages }); // chat()

    stream mode accepts array and function inputs to match wait mode, and all entry points now route through a shared internal admission path that throws a clear error on nested blocking admissions that previously could deadlock.

    Recovery and reliability

    A large part of this release continues hardening recovery and converging @cloudflare/think and @cloudflare/ai-chat onto one model:

    • Stream stall watchdog. AIChatAgent can detect and recover from a hung model/transport stream via the opt-in chatStreamStallTimeoutMs watchdog. With chatRecovery enabled the stall routes into the same bounded-recovery machinery a deploy or eviction uses; otherwise it surfaces as a terminal stream error so the spinner clears.
    • Interrupted tool-call repair. AIChatAgent now repairs a transcript with a dead server-tool call before re-entering inference (parity with @cloudflare/think), so a recovered turn no longer fails with AI_MissingToolResultsError. An overridable repairInterruptedToolPart(part) hook lets apps customize the repaired shape.
    • Stuck status after reconnect. Fixed AI SDK status getting stuck when a reconnect races a turn that has been accepted but has not started streaming yet, so the UI now renders the in-flight turn instead of settling on ready.
    • Live "recovering…" on connect. AIChatAgent now replays the recovering status to a client that connects mid-recovery, so useAgentChat's isRecovering reflects in-progress recovery immediately instead of appearing frozen.
    • Terminal connection failures. The client stops reconnecting on terminal WebSocket close events and exposes them via connectionError / onConnectionError on AgentClient, useAgent, and useAgentChat.
    • Agent-tool child recovery. A healthy long-running sub-agent run is no longer abandoned as interrupted after a deploy (both @cloudflare/think and AIChatAgent).
    • Workflows from sub-agent facets. Agent Workflows can now start from sub-agent facets, with callbacks and Workflow RPC routed back to the originating facet.
    • Plus forward-progress crediting convergence, broadcast-first give-up ordering, an event-driven auto-continuation barrier, and structured row-size compaction in AIChatAgent.

    Other improvements

    • Shared chat React core. A new agents/chat/react entry exposes useAgentChat, transport helpers, and shared wire types, with syncMessagesToServer for server-authoritative transcript storage. @cloudflare/think/react and @cloudflare/ai-chat/react are now thin wrappers over it.
    • Optional ai peer. The root agents and @cloudflare/codemode runtimes no longer reference AI SDK types, so they bundle without ai / zod installed; AI-specific entry points still require the peer when imported. just-bash likewise moves to an optional peer used only by the skills bash runner.
    • Code Mode. The default DynamicWorkerExecutor timeout increases from 30s to 60s, executions now dispose the dynamically-loaded Worker and its RPC stub after each run (fixing a flaky isolate-shutdown assertion), connector imports are cleaned up, and the outer MCP tool-call context is passed to openApiMcpServer request callbacks.
    • Voice. Voice turns now support AI SDK fullStream responses (and warn when textStream is used).
    • MCP. McpAgent server-to-client requests can now be sent from callbacks that do not inherit the agent's async context, including callbacks reached through Worker Loader RPC.
    • Experimental: server actions and channels. This release lays groundwork for guarded server actions (action() / getActions() with a durable replay ledger and approvals) and a unified channels surface (configureChannels(), deliverNotice()). Both are experimental and their APIs may change, so we don't recommend depending on them yet.

    Upgrade

    To update to the latest version:

    npm i agents@latest @cloudflare/think@latest @cloudflare/ai-chat@latest @cloudflare/codemode@latest @cloudflare/voice@latest

    Refer to the Think documentation, Code Mode documentation, and Agents documentation for more information.

  1. Durable Objects now supports a us jurisdiction, letting you create Durable Objects that only run and store data within the United States. Use the us jurisdiction when you need to keep a Durable Object's compute and storage inside the United States to meet data residency requirements.

    Create a namespace restricted to the us jurisdiction the same way as any other jurisdiction:

    JavaScript
    // Worker
    export default {
    async fetch(request, env) {
    const usSubnamespace = env.MY_DURABLE_OBJECT.jurisdiction("us");
    const stub = usSubnamespace.getByName("general");
    return stub.fetch(request);
    },
    };

    Workers may still access Durable Objects constrained to the us jurisdiction from anywhere in the world. The jurisdiction constraint only controls where the Durable Object itself runs and persists data.

    For the full list of supported jurisdictions, refer to Data location — Restrict Durable Objects to a jurisdiction.

  1. The @cloudflare/vitest-pool-workers package now includes evictDurableObject and evictAllDurableObjects test helpers, exported from cloudflare:test.

    These helpers let you test how a Durable Object behaves across evictions, simulating the production lifecycle where an idle Durable Object can be evicted from memory.

    For more context, refer to Lifecycle of a Durable Object.

    TypeScript
    import { evictDurableObject, evictAllDurableObjects } from "cloudflare:test";
    import { env } from "cloudflare:workers";
    const id = env.COUNTER.idFromName("my-counter");
    const stub = env.COUNTER.get(id);
    // Evict the Durable Object instance pointed to by a specific stub
    await evictDurableObject(stub);
    // Close WebSockets instead of hibernating them
    await evictDurableObject(stub, { webSockets: "close" });
    // Evict all currently-running Durable Objects in evictable namespaces
    await evictAllDurableObjects();

    These helpers are available in @cloudflare/vitest-pool-workers@0.16.20 and later.

    Learn more in the Test APIs reference and the Testing Durable Objects guide.

  1. Durable Objects now supports two new location hints for Asia-Pacific: apac-ne (Northeast Asia-Pacific) and apac-se (Southeast Asia-Pacific). Use apac-ne or apac-se when you want finer-grained placement within Asia-Pacific rather than the broader apac hint.

    Use the new hints the same way as any other locationHint:

    JavaScript
    // Northeast Asia-Pacific (Japan, Korea, etc.)
    const stubNE = env.MY_DURABLE_OBJECT.get(id, { locationHint: "apac-ne" });
    // Southeast Asia-Pacific (Singapore, Indonesia, etc.)
    const stubSE = env.MY_DURABLE_OBJECT.get(id, { locationHint: "apac-se" });

    If your users are spread across all of Asia-Pacific, the existing apac hint remains the right choice. Only reach for apac-ne or apac-se when your traffic is clearly concentrated in one sub-region and you want to minimize round-trip time to that audience. The default behavior and what we generally recommended is not adding a location hint unless absolutely needed, this will create the Durable Object as close to the initializing request as possible to reduce latency.

    As with all location hints, these are best-effort suggestions. Cloudflare will place the Durable Object in a nearby data center, not necessarily the exact hinted location.

    For the full list of supported hints, refer to Data location — Provide a location hint.

  1. AI agents can now deploy Workers to Cloudflare without first requiring a user to sign up, open a browser-based OAuth flow, click through the dashboard, or create an API token. When an agent tries to deploy without Cloudflare credentials, Wrangler can tell it to rerun with --temporary, then deploy the Worker to a temporary preview account.

    To try this with your agent, update to Wrangler 4.102.0 or later, make sure you are logged out (wrangler logout), and then ask your agent to build something and deploy it to Cloudflare. The agent should follow Wrangler's output and deploy using the --temporary flag.

    Diagram showing an AI agent deploying, verifying, and redeploying a Worker to a temporary account, then claiming it after authentication and moving it to a permanent account
    Terminal window
    wrangler deploy --temporary

    The temporary deployment stays live for 60 minutes. During that window, the agent can verify the Worker, redeploy changes, and return both the live Worker URL and claim URL. Opening the claim URL lets you sign in to or create a Cloudflare account and make the temporary account permanent.

    Temporary preview accounts currently support a limited set of products, including Workers, Workers Static Assets, Workers KV, D1, Durable Objects, Hyperdrive, Queues, and SSL/TLS certificates. For supported products, limits, and claim behavior, refer to Claim deployments (temporary accounts).

    For more context, refer to Temporary Cloudflare Accounts for Agents.

  1. You can create PlanetScale Postgres and MySQL databases from Cloudflare and bill PlanetScale database usage through your Cloudflare account as a pay-as-you-go customer. Cloudflare contract customers will be able to add PlanetScale usage to their contract in July so reach out to your Cloudflare account team if interested.

    Create a PlanetScale database from the Cloudflare dashboard to check out globally distributed Workers optimized for regional data access.

    Go to Create a PlanetScale database Request flow from a user to Workers, Hyperdrive caches, connection pools, and PlanetScale.

    PlanetScale databases created from Cloudflare work with Workers through Hyperdrive. Hyperdrive manages database connection pools and query caching, so you can use PlanetScale as a centralized relational database for Workers applications without changing your database drivers, object-relational mapping (ORM) libraries, or SQL tooling.

    PlanetScale usage appears on your Cloudflare invoice each billing period as a dollar total at PlanetScale's standard pricing. You can introspect per-database billing usage via PlanetScale's dashboard.

    When you create a PlanetScale database from the Cloudflare dashboard, you receive the same PlanetScale developer experience, including development branches, query insights, and Model Context Protocol (MCP) server support for agents.

    To get started, refer to PlanetScale Postgres and MySQL with Hyperdrive.

  1. The latest release of the Agents SDK makes it easier to build agents that can safely interact with real systems and keep working through interruptions.

    Agents can now browse websites through Browser Run, write code against external tools through Code Mode, use client-provided tools when delegating to Think sub-agents, and recover more reliably from deploys, Durable Object evictions, and connection churn.

    Safer browser automation

    Agents can now use Browser Run through a single durable browser_execute tool. Instead of choosing from a fixed list of actions, the model writes code against the Chrome DevTools Protocol (CDP) and can inspect pages, capture screenshots, read rendered content, debug frontend behavior, and interact with live browser sessions.

    JavaScript
    const browserTools = createBrowserTools({
    ctx: this.ctx,
    browser: this.env.BROWSER,
    loader: this.env.LOADER,
    session: { mode: "dynamic" },
    });

    Browser sessions can be one-time, reused, or promoted from one-time to persistent during a run. This is useful when an agent needs a human to log in, complete MFA, or approve a sensitive action. The run can pause, keep the same tabs and cookies, and resume after approval.

    The browser tools also add Live View URLs, optional session recording, and quick actions such as browser_markdown, browser_extract, browser_links, and browser_scrape for one-shot browsing tasks.

    Resumable code execution with approvals

    Code Mode now uses createCodemodeRuntime, connectors, and a durable execution log. This lets you give a model one codemode tool instead of a large prompt full of tool definitions. The model can discover the capabilities it needs, write code against typed globals, and reuse saved snippets.

    JavaScript
    const runtime = createCodemodeRuntime({
    ctx: this.ctx,
    executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }),
    connectors: [new GithubConnector(this.ctx, this.env, connection)],
    });
    const result = streamText({
    model,
    messages,
    tools: { codemode: runtime.tool() },
    });

    When the code reaches an approval-gated action, the runtime pauses execution and returns a pending approval. After approval, completed calls replay from the durable log, the approved action runs, and the same code continues. This makes it practical to build agents that create issues, update external systems, or perform other side effects without custom pause-and-resume logic for every tool.

    Better Think delegation

    Think sub-agents can now use client-defined tools over the RPC chat() path. A parent agent can pass tool schemas with clientTools and resolve tool calls through onClientToolCall. This lets delegated agents use caller-provided capabilities without requiring a browser WebSocket.

    JavaScript
    await child.chat(message, callback, {
    signal,
    clientTools: [
    {
    name: "get_user_timezone",
    description: "Get the caller's timezone",
    parameters: { type: "object" },
    },
    ],
    onClientToolCall: async ({ toolName, input }) => {
    return runClientTool(toolName, input);
    },
    });

    Think Workflows also improve step.prompt(). A prompt step now runs a full agentic turn before returning structured output, so the agent can call tools before producing the typed result. This makes Workflow steps more useful for durable triage, research, and approval flows.

    The unified Think execute tool can also include cdp.* browser capabilities alongside state.* and tools.* when Browser Run is bound.

    Voice output device selection

    Voice clients can route assistant audio to a specific output device. Use outputDeviceId with useVoiceAgent, or call client.setOutputDevice() from the framework-agnostic client.

    JavaScript
    const voice = useVoiceAgent({
    agent: "MyVoiceAgent",
    outputDeviceId: selectedSpeakerId,
    });

    Browsers without speaker-selection support continue playing through the default output device and report a non-fatal outputDeviceError.

    Reliability fixes

    This release includes several fixes for production agents:

    • useAgent and AgentClient handle WebSocket replacement more reliably during reconnects and configuration changes.
    • Chat stream replay is more reliable after reconnects, deploys, and provider errors.
    • Fiber recovery continues across multi-pass scans and backs off when recovery hooks keep failing.
    • Agent teardown continues even when the request that started teardown is canceled.
    • Large session histories use byte-budgeted reads to reduce memory pressure during startup.

    Upgrade

    To update to the latest version:

    npm i agents@latest @cloudflare/think@latest @cloudflare/codemode@latest @cloudflare/ai-chat@latest @cloudflare/voice@latest

    Refer to the Code Mode documentation, Browser tools documentation, Think tools documentation, and Voice documentation for more information.

  1. We are excited to announce GLM-5.2 on Workers AI, Z.ai's flagship agentic coding model.

    @cf/zai-org/glm-5.2 is a text generation model built for agentic coding workflows. With function calling and reasoning support, it can handle long codebases, multi-step planning, and tool-augmented agents.

    Key features and use cases:

    • Agentic coding: Designed for autonomous coding tasks, long-horizon planning, and complex software engineering workflows
    • Large context window: GLM-5.2 supports up to a 1,048,576 token context window. Workers AI is launching the model with a 262,144 token context window and plans to increase this in the future
    • Function calling: Build agents that invoke tools and APIs across multiple conversation turns
    • Reasoning: Tackles complex problem-solving and step-by-step reasoning tasks

    Use GLM-5.2 through the Workers AI binding (env.AI.run()), the REST API at /run or /v1/chat/completions, or AI Gateway.

    Pricing is available on the model page or pricing page.

  1. You can now create custom trace spans in your Workers code using tracing.enterSpan(). Custom spans appear alongside the automatic platform instrumentation (fetch calls, KV reads, D1 queries, and other platform operations) in your traces and OpenTelemetry exports, with correct parent-child nesting.

    The API is available via import { tracing } from "cloudflare:workers" or through the handler context as ctx.tracing:

    TypeScript
    import { tracing } from "cloudflare:workers";
    export default {
    async fetch(request, env, ctx) {
    return tracing.enterSpan("handleRequest", async (span) => {
    span.setAttribute("url.path", new URL(request.url).pathname);
    const data = await env.MY_KV.get("key");
    return new Response(data);
    });
    },
    };

    Spans nest automatically based on the JavaScript async context, and are auto-ended when the callback returns or its returned promise settles. The Span object provides setAttribute(key, value) for attaching metadata and an isTraced property to check whether the current request is being sampled.

    Trace waterfall showing custom spans nested alongside automatic KV and fetch instrumentation

    Tracing must be enabled in your Wrangler configuration for spans to be recorded.

    For full API details and examples, refer to Custom spans.

  1. You can now filter the Metrics tab for a Durable Objects namespace by an individual Durable Object's ID or name in the Cloudflare dashboard. Previously, metrics charts only showed aggregate, namespace-level data, making it difficult to isolate the behavior of a specific object.

    Go to Durable Objects The Durable Objects Metrics tab filtered to a single object by ID, showing per-object requests and errors by invocation status.

    Start typing an ID or name into the filter and select a match from the autocomplete dropdown. The autocomplete only shows objects with invocations during the selected time range, so an object that does not appear has not been invoked in that window. This does not necessarily mean the object has been deleted. Every chart on the page updates to reflect only the selected object. This makes it easier to identify and investigate a single Durable Object when debugging a high-traffic object, an error spike, or unexpected storage usage. Clear the filter to return to namespace-level metrics.

    Metrics are powered by the GraphQL Analytics API, so standard analytics behavior such as ingestion delay and sampling applies.

    For more information, refer to Metrics and analytics.

  1. Dynamic Workers usage on the Workers overview page

    Customers can now view the number of Dynamic Workers invoked during their billing period from the Workers overview page in the Cloudflare dashboard.

    This count reflects the number of Dynamic Workers that Cloudflare would bill for during the selected billing period. Dynamic Workers usage data only goes back to June 1, 2026.

    You can also query this count through the GraphQL Analytics API by using workersInvocationsByOwnerAndScriptGroups and selecting distinctDynamicWorkerCount:

    query getDynamicWorkersCount(
    $accountTag: string!
    $filter: AccountWorkersInvocationsByOwnerAndScriptGroupsFilter_InputObject
    ) {
    viewer {
    accounts(filter: { accountTag: $accountTag }) {
    workersInvocationsByOwnerAndScriptGroups(limit: 10000, filter: $filter) {
    uniq {
    distinctDynamicWorkerCount
    }
    }
    }
    }
    }

    Use variables to set the account and billing-period date range:

    {
    "accountTag": "<ACCOUNT_ID>",
    "filter": {
    "date_geq": "2026-06-01",
    "date_leq": "2026-06-30"
    }
    }

    For more information, refer to Dynamic Workers pricing.

  1. Pay-as-you-go customers can now view billable usage and create budget alerts directly from the product overview pages for Workers & Pages, D1, R2, Workers KV, Queues, Vectorize, Durable Objects, and Containers. A new sidebar widget shows current-period spend and the billing cycle date range, alongside a button to create a budget alert.

    The widget pulls from the same data as the Billable Usage dashboard and aligns to your billing cycle (or the current day on Free plans), so the numbers match your invoice. Enterprise contract accounts are not yet supported.

    Billable usage widget in the Durable Objects product sidebar showing current-period spend and a breakdown by service

    Selecting Create budget alert opens the budget alert flow inline so you can set a dollar threshold in the same place you are reviewing usage. Budget alerts apply to your total account-level spend across all products, not just the product page you create them from.

    For more information, refer to the Usage-based billing documentation.

  1. The pipeline field inside the pipelines binding configuration in your Wrangler configuration file has been renamed to stream. The old field is deprecated but still accepted.

    Update your configuration to use stream to avoid the deprecation warning.

    Before (deprecated):

    JSONC
    {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "pipelines": [
    {
    "binding": "MY_PIPELINE",
    "pipeline": "<STREAM_ID>"
    }
    ]
    }

    After:

    JSONC
    {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "pipelines": [
    {
    "binding": "MY_PIPELINE",
    "stream": "<STREAM_ID>"
    }
    ]
    }

    No other changes are required. The binding name, TypeScript types, and runtime API (env.MY_PIPELINE.send(...)) remain the same.

    For more information on configuring pipeline bindings, refer to Writing to streams.

  1. You can now create, update, or delete multiple secrets for your Worker in a single request using the bulk secrets endpoint.

    • Include a secret with a value to create or update.
    • Set a secret to null to delete.
    • Secrets not included in the request are left unchanged.

    The following example creates API_KEY, updates the already existing DB_PASSWORD, and deletes OLD_SECRET:

    {
    "secrets": {
    "API_KEY": { "type": "secret_text", "name": "API_KEY", "text": "my-api-key" },
    "DB_PASSWORD": { "type": "secret_text", "name": "DB_PASSWORD", "text": "my-db-password" },
    "OLD_SECRET": null
    }
    }

    You can do the same from the command line using wrangler secret bulk:

    Terminal window
    npx wrangler secret bulk < secrets.json

    To delete a key, set its value to null in the JSON file. Deletion is not supported with .env files.

    Each request supports up to 100 total operations (creates, updates, and deletes combined).

  1. Wrangler can now store the OAuth credentials returned by wrangler login in an AES-256-GCM-encrypted file, with the encryption key held in your operating system keychain. The default behavior is unchanged — credentials still live in a plaintext TOML file unless you opt in.

    To opt in, run:

    Terminal window
    npx wrangler login --use-keyring

    The choice is persisted across Wrangler invocations. Opt back out with npx wrangler login --no-use-keyring, or override the preference for a single command with the CLOUDFLARE_AUTH_USE_KEYRING environment variable.

    wrangler whoami now reports where credentials are stored:

    🔐 Credentials are stored in: Encrypted file (~/.config/.wrangler/config/default.enc) with key in macOS Keychain (service=wrangler, account=default)

    Per-platform backends:

    • macOS uses the built-in Keychain via /usr/bin/security.
    • Linux uses libsecret via the secret-tool CLI from the libsecret-tools package.
    • Windows uses Credential Manager via @napi-rs/keyring, installed on-demand the first time you opt in.

    Refer to Storing OAuth credentials in the OS keychain for the full details, including the migration behavior on opt-in/opt-out and the CLOUDFLARE_AUTH_USE_KEYRING environment variable.