NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #1829 most downloaded on npm
Fun, full-featured, fully-local simulator for Cloudflare Workers
Last release 3 days ago
01 Oct 2026
Ships on a steady schedule
a new release about every 1 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
50 versions withdrawn
withdrawn after publishing
5 years old
1670 releases · first in 2021
One column per quarter.
…matching the runtime API while preserving the deprecated array form.
#15970 b00ef4f Thanks @wperron! - Keep local development responsive while capturing observability data
Local observability now records high volumes of spans and logs with less impact on the main Worker, making local requests faster and more responsive. If observability data arrives faster than it can be stored, completed entries are dropped rather than slowing the Worker; the buffer size can be tuned with X_LOCAL_OBSERVABILITY_BATCH_SIZE.
#15777 464a582 Thanks @Naapperas! - Support the new Workflows createBatch() API in local development
Local Workflows bindings now accept object-form batches that create instances from a count or a list of instance options. The result includes handles for created instances and indexed per-instance errors, matching the runtime API while preserving the deprecated array form.
#15984 9d7b08e Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260930.2 | ^5.20261001.1 |
| workerd | 1.20260930.2 | 1.20261001.1 |
Declare the zero-configuration binding in wrangler.json with "analytics": { "binding": "ANALYTICS" } . Wrangler uploads the analytics binding type and
#15685 b9f1cdc Thanks @Ankcorn! - Add native support for the Analytics SQL binding
Declare the zero-configuration binding in wrangler.json with "analytics": { "binding": "ANALYTICS" }. Wrangler uploads the analytics binding type and proxies it to the remote service during local development, so wrangler dev can call the binding without unsafe.bindings.
#15948 a0712e5 Thanks @akoval-cf! - Add beta K2 producer bindings for existing streams
Configure a stream created through Wrangler, the Dashboard, or the API in wrangler.json:
The binding supports env.ORDERS.send([{ content: new TextEncoder().encode("order"), headers: { event: "order.created" } }]). Batches use either all ArrayBuffer or all Uint8Array content. Check the returned success value, handle rejected RPC promises, and retry only when the returned error explicitly allows it. Generated environment types describe this producer contract without requiring a separate application dependency.
K2 requires an enabled account. Deployment credentials need Worker deployment and K2 configuration-read access. Default Wrangler logins now request the K2 OAuth scopes; existing OAuth users should run wrangler login again to grant the new permissions. Development always uses a real K2 stream and may incur usage charges; no local simulator is provided. The remote setting can be omitted, remote: true suppresses the usage warning, and remote: false is rejected. Consumption is not part of this Worker binding.
#15908 ddaa558 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260926.1 | ^5.20260930.2 |
| workerd | 1.20260926.1 | 1.20260930.2 |
This updates the RPC implementation shipped in Miniflare and remote-binding proxy workers to the latest capnweb release.
#15923 60ccdbd Thanks @petebacondarwin! - Upgrade the bundled capnweb implementation to 0.12.0
This updates the RPC implementation shipped in Miniflare and remote-binding proxy workers to the latest capnweb release.
#15938 62fd03a Thanks @dieub! - Resolve the affected Undici dependency in new Wrangler and Vite plugin installs
Undici 7.29.1 fixes GHSA-3wwx-pv8p-q78v. Update the shared dependency catalog and matching types used by Miniflare and Wrangler so downstream installs can resolve the patched runtime without an application-level override. A published release is still required for consumers; this changeset does not alter already published package metadata.
#15902 c2bb4c8 Thanks @michealroberts! - Fix passing an R2ObjectBody#body back to R2Bucket#put() via Miniflare#getR2Bucket()
Previously, a body returned by get() lost its length on the way back through the binding proxy, so put() rejected it with "Provided readable stream must have a known length", even though the same call works in a Worker. The proxy now forwards the stream's length and the body streams straight through without buffering.
#15906 eb1efe0 Thanks @michealroberts! - Preserve the request body length in Miniflare#dispatchFetch()
Previously, a request with a known-length body (e.g. a string) was sent to the Worker chunked, without a Content-Length. Passing its request.body to R2Bucket#put() then failed with "Provided readable stream must have a known length", even though the same request works in production. The body's length is now preserved.
#15910 485cfb3 Thanks @james-elicx! - Raise the local R2 custom metadata limit to 8 KiB
R2 put() now accepts up to 8,192 bytes of custom metadata, matching the documented R2 limit. Previously, Miniflare rejected metadata larger than 2 KiB.
Multipart upload creation now enforces the same limit through both R2 bindings and the local S3 API. Oversized metadata is rejected with error 10012 through R2 bindings, or HTTP 400 MetadataTooLarge for S3 uploads, copies, and multipart initiation.
A Workflow declared in a Worker's exports is now available on ctx.exports in wrangler dev , the Vite plugin and the Vitest plugin, with the same API a
#15856 4c2993b Thanks @Naapperas! - Support Workflows declared in exports on ctx.exports in local development
A Workflow declared in a Worker's exports is now available on ctx.exports in wrangler dev, the Vite plugin and the Vitest plugin, with the same API as a Workflow binding:
const instance = await ctx.exports.MyWorkflow.create({
params: { name: "World" },
});ctx.exports and workflows bindings with the same Workflow name share their instances, including instances created before the Workflow was declared in exports. Two Workers can't export the same Workflow name, and a binding to an exported Workflow must refer to the Worker and class that export it. getPlatformProxy() ignores Workflows declared in exports, since it doesn't run the Worker's code.
wrangler workflows commands run with --local also work with Workflows declared only in exports, without a workflows binding.
In the Vitest plugin, introspectWorkflow() and introspectWorkflowInstance() still need a Workflow binding, and now explain how to add one when passed a Workflow from ctx.exports. Instances created through ctx.exports are introspected too. A workflows binding whose script_name is the Worker's own name now resolves to the Worker itself again.
#15891 8dc53ae Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260925.1 | ^5.20260926.1 |
| workerd | 1.20260925.1 | 1.20260926.1 |
The following dependency versions have been updated:
#15864 ee2b200 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260923.1 | ^5.20260925.1 |
| workerd | 1.20260923.1 | 1.20260925.1 |
#15676 c91279b Thanks @L4XB! - Fix QuotaExceededError when a producer sends many queue messages locally
The local Queues broker registered a timer for every message it received, including messages with no delivery delay. workerd caps a Durable Object at 10000 active timeouts and none of those timers run while the producer is still sending, so a Worker that enqueued more than 10000 messages in one go failed with QuotaExceededError: You have exceeded the number of active timeouts you may set.
Messages without a delivery delay are now enqueued directly, and only delayed messages use a timer. This matches what the broker already did under Miniflare's fake timers, where a zero-delay timer runs synchronously.
Miniflare's V4 Worker options now accept exact Cron Trigger expressions. Local Explorer reports them in Worker metadata and can dispatch a scheduled e
#15648 52c0e9f Thanks @tpmmorris! - Expose configured Cron Triggers and one-off scheduled dispatch through Local Explorer
Miniflare's V4 Worker options now accept exact Cron Trigger expressions. Local Explorer reports them in Worker metadata and can dispatch a scheduled event to an exact local or peer Worker name with a chosen cron expression and time.
#15652 44f5295 Thanks @tpmmorris! - Package the Cron Triggers interface in Local Explorer
The Local Explorer assets now include an interactive Cron Triggers destination for one-off local scheduled-handler testing.
#15786 bdda4c3 Thanks @ThomasRubini! - Support UDP connect handlers in local development
The experimental connect configuration now accepts protocol: "udp", with optional idle_timeout_ms and max_pending_bytes settings. UDP datagrams are delivered to the Worker's connect() handler using workerd's value-mode socket streams, and can be tested with Miniflare#dispatchConnect({ protocol: "udp" }).
#15779 fc3cbaa Thanks @Naapperas! - Support workflow entries in the exports configuration map
A Worker can now declare the Workflows it defines in exports, keyed by the WorkflowEntrypoint class name:
{
"exports": {
"MyWorkflow": {
"type": "workflow",
"name": "my-workflow",
"limits": { "steps": 100 },
"schedules": "0 * * * *"
}
}
}A workflow export accepts the same settings as a workflows binding: limits, concurrency, schedules, and default_retention. wrangler deploy and wrangler versions upload send these entries to the upload API by name, and wrangler deploy and wrangler triggers deploy provision the Workflow with its settings, just as they do for workflows bindings owned by the Worker. A Workflow may be declared both as a binding and as an export, as long as both declarations use the same class and do not set the same setting to different values. A binding to another Worker's Workflow cannot share a name with an export. @cloudflare/config adds the matching exports.workflow() helper. Local development does not yet act on these entries.
#15796 be72815 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260921.1 | ^5.20260923.1 |
| workerd | 1.20260921.1 | 1.20260923.1 |
#14847 940c692 Thanks @TheSaiEaranti! - Emulate the deterministic-ID uniqueness contract in the local Workflows binding
The local Workflows binding now matches the documented production behavior for deterministic instance IDs: create({ id }) with an ID that already exists throws (instance.already_exists) and retains the existing instance, and createBatch() skips IDs that already exist or repeat within the batch, excluding them from the result instead of creating duplicate executions. Previously both paths silently created duplicates, so code relying on deterministic IDs for idempotency (for example a Queue consumer creating one workflow per message) appeared to work locally while double-executing workflow bodies.
Routing captures can now be resent directly or loaded into the test email composer for editing. Routing rows expose and use a UUID-based capture ID fo
#15567 a71237a Thanks @tpmmorris! - Add row-level email resend tools to the Local Explorer
Routing captures can now be resent directly or loaded into the test email composer for editing. Routing rows expose and use a UUID-based capture ID for identity, detail lookup, and resend operations instead of relying on the email's Message-ID. Message-ID detail lookup remains available for compatibility, and resends preserve partial-capture warnings across replayed messages.
Worker configs passed to Miniflare no longer require or accept type: "worker" . Nested Worker binding and export discriminators are unchanged.
#15713 3c75cad Thanks @jamesopstad! - Remove the top-level Worker discriminator from Miniflare options
Worker configs passed to Miniflare no longer require or accept type: "worker". Nested Worker binding and export discriminators are unchanged.
#15740 c5913a6 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260918.1 | ^5.20260921.1 |
| workerd | 1.20260918.1 | 1.20260921.1 |
The following dependency versions have been updated:
#15705 a0485d5 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260917.1 | ^5.20260918.1 |
| workerd | 1.20260917.1 | 1.20260918.1 |
Miniflare now accepts named image references for Durable Object-managed Containers and preserves an omitted default image ( imageName ). A Container w
#15672 2298cf1 Thanks @ghostwriternr! - Support named images or no default image for Durable Object-managed Containers
Miniflare now accepts named image references for Durable Object-managed Containers and preserves an omitted default image (imageName). A Container without a default image must supply an image or full Container snapshot when starting.
This extends Miniflare's experimental Durable Object-managed Containers interface.
#15689 876eea1 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260916.1 | ^5.20260917.1 |
| workerd | 1.20260916.1 | 1.20260917.1 |
Local Explorer and Wrangler local mode now use the production-compatible status request field for pausing, resuming, restarting, and terminating Workf
#15483 71b6f10 Thanks @tpmmorris! - Align Local Explorer Workflow instance status requests with production
Local Explorer and Wrangler local mode now use the production-compatible status request field for pausing, resuming, restarting, and terminating Workflow instances. Direct Local Explorer API consumers must replace the previous action field with status.
Successful Local Explorer status updates now return the production-compatible instance status and response timestamp instead of the local-only result.success acknowledgement.
#15665 ad23e6e Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260915.1 | ^5.20260916.1 |
| workerd | 1.20260915.1 | 1.20260916.1 |
#15552 6f3d7b5 Thanks @superbuilder-norm! - Prevent synchronous binding calls from failing intermittently under load
Miniflare now keeps synchronous binding requests and responses correctly paired when background work is delayed. This prevents rare cascades of assertion failures in local development and CI, including when using synchronous D1 methods such as prepare() and bind().
API clients can now write and delete multiple local KV entries by changing only their Cloudflare API base URL. The new routes support production reque
#15486 d3565a5 Thanks @tpmmorris! - Add production-compatible KV bulk write and delete routes to Local Explorer
API clients can now write and delete multiple local KV entries by changing only their Cloudflare API base URL. The new routes support production request and response shapes, including base64 values, expiration options, and metadata.
#15453 ca71205 Thanks @G4brym! - Remove the gated Web Search binding and Wrangler command
The unreleased search binding and its experimental command have been removed from Wrangler, Miniflare, and configuration APIs.
#15633 7db596c Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260911.1 | ^5.20260915.1 |
| workerd | 1.20260911.1 | 1.20260915.1 |
#15420 e35c4a1 Thanks @manthaaaaan! - Fix Infinity/-Infinity being emitted as an invalid bare identifier in D1 export
#15527 1015cfb Thanks @devaniketh! - Scope Durable Object and Workflow local explorer peers by storageScope
Restricts Durable Object and Workflow peer discovery and owner resolution to Miniflare peers sharing the same storageScope when Shared Storage is enabled. This ensures consistency with KV, D1, and R2 local explorer behaviors and prevents cross-project access to local development state across instances with different persistence roots.
#15399 982b806 Thanks @tpmmorris! - Improve over-limit run_worker_first errors when duplicate rules are present
The error now reports distinct and duplicate-entry counts and lists duplicated rules, making it clear when removing redundant entries can bring the configuration within the limit.
Too many `run_worker_first` rules were provided; 105 rules provided (99 distinct, 6 duplicate entries) exceeds max of 100. Note: duplicate entries count towards the route limit. Ensure that no duplicate rules are present in your `run_worker_first` configuration.
The duplicated rules found are:
- "/rule/0"
- "/rule/1"
- "/rule/2"
- "/rule/3"
- "/rule/4"
...and 1 more duplicated rule.
#15397 641df47 Thanks @james-elicx! - Reduce Miniflare's bundle size by sharing Zod across embedded workers
Workflows, Email Store, and Local Explorer now import Zod from Miniflare's existing workerd extension instead of each bundling a separate copy.
Local Workflow instances now implement subscribe() , returning a disposable RPC subscription that streams historical and live lifecycle events. Subscr
#15441 8997652 Thanks @mkuritsu! - Add experimental Workflow event subscriptions to local development
Local Workflow instances now implement subscribe(), returning a disposable RPC subscription that streams historical and live lifecycle events. Subscriptions support event cursors and type filters and include Workflow inputs, status transitions, step configuration, outputs, errors, retries, waits, and rollback activity where applicable.
The following dependency versions have been updated:
#15602 47d906f Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260910.1 | ^5.20260911.1 |
| workerd | 1.20260910.1 | 1.20260911.1 |
#15121 c2699bf Thanks @HaoChiBao! - Fix Durable Object stub.fetch rejecting Node's global Request
Passing a Node.js global Request object to a Durable Object stub's fetch() (for example when using getPlatformProxy) previously failed with a URL parsing error. Such requests are now accepted and forwarded as expected.
…that addresses GHSA-rgj7-g3m4-5g8c , covering vulnerabilities in its bundled libheif library.
#15578 15cd6e1 Thanks @ThomasRubini! - Add Miniflare#dispatchConnect() for testing Worker TCP handlers
Tests can now open a Node.js socket to a Worker's configured TCP trigger without reserving and connecting to a fixed port manually. Miniflare waits for startup, resolves OS-assigned ports, supports selecting Workers and triggers, and closes dispatched sockets during disposal.
#15432 f45b596 Thanks @razethion! - Prevent delayed internal errors from fetch-only remote bindings
Fetch-only remote bindings such as D1 and R2 previously opened an unused WebSocket RPC session. RPC sessions are now created only when an RPC method is called.
#15585 f69f95a Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260908.1 | ^5.20260910.1 |
| workerd | 1.20260908.1 | 1.20260910.1 |
#14814 a549e58 Thanks @chinesepowered! - Match Content-Type case-insensitively when simulating Cloudflare's response compression
Locally, responses were only compressed when the Content-Type matched the compressible media type list exactly. Because HTTP media types are case-insensitive and may carry whitespace before their parameters, headers such as Application/JSON or text/html ; charset=utf-8 were treated as non-compressible, diverging from production behaviour. The media type is now trimmed and lowercased before matching.
#15540 dbb3ff4 Thanks @NAVEENKUMARKR777! - Fix DevalueError: Cannot stringify arbitrary non-POJOs when passing a Headers instance to a proxied binding method
R2Object#writeHttpMetadata(), R2Bucket#put()'s onlyIf option, and other proxied APIs that accept a Headers argument previously only worked if that Headers instance came from the exact same Headers implementation Miniflare uses internally (undici). In practice, user code almost always constructs Headers using the platform global instead (for example inside Next.js, Astro, Remix, or SvelteKit dev servers), which is backed by a different copy of undici and isn't instanceof the one Miniflare imports. This mismatch caused serialisation to fail with a confusing DevalueError, even though the exact same code worked fine when deployed.
Headers, Request, and Response values are now also recognised by their Symbol.toStringTag, which is realm-independent, so any spec-compliant instance is accepted regardless of which copy of the class created it.
#15485 fea3cd0 Thanks @RealBhupesh! - Reject loopback server bind failures during Miniflare startup instead of leaving ready and dispose() hanging
#startLoopbackServer now attaches an error listener before listen, matching the inspector proxy. When the configured host cannot be bound (e.g. 192.0.2.1), ready rejects and dispose() still settles even if the loopback server never started.
#15580 6bd7b6c Thanks @petebacondarwin! - Update sharp to 0.35.4
This updates the image-processing dependency used by Miniflare's local Images binding to a version that addresses GHSA-rgj7-g3m4-5g8c, covering vulnerabilities in its bundled libheif library.
#15515 be1caec Thanks @Wichtowski! - Handle Miniflare listener startup failures consistently
Loopback and inspector servers now remove startup-only error handlers after binding and close the server after bind failures. Inspector bind failures are observed immediately and propagated through readiness, URL access, and disposal.
#15403 dbc9506 Thanks @james-elicx! - Reduce the size of Miniflare's embedded asset and router Workers
Miniflare does not configure Sentry credentials for its asset services, so their builds now replace the unused production Sentry setup with a no-op instead of bundling Toucan.
Flagship bindings can now evaluate flags against a persisted local store instead of requiring a remote app. Miniflare also exposes an admin API for po
#15268 bcebf08 Thanks @akshitsinha! - Simulate Flagship bindings locally
Flagship bindings can now evaluate flags against a persisted local store instead of requiring a remote app. Miniflare also exposes an admin API for populating and managing that store in development tools and tests, while bindings configured for remote access continue to proxy to Flagship.
#15560 edb3631 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260907.1 | ^5.20260908.1 |
| workerd | 1.20260907.1 | 1.20260908.1 |
The following dependency versions have been updated:
#15502 8bbcb9f Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260903.1 | ^5.20260904.1 |
| workerd | 1.20260903.1 | 1.20260904.1 |
#15543 2b42d6f Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260904.1 | ^5.20260907.1 |
| workerd | 1.20260904.1 | 1.20260907.1 |
D1, KV and R2 operations now address Miniflare's internal storage services directly, so they no longer require configured bindings. Shared-storage ses
#15401 00a9f2f Thanks @penalosa! - Allow Local Explorer storage APIs to access arbitrary local resource IDs
D1, KV and R2 operations now address Miniflare's internal storage services directly, so they no longer require configured bindings. Shared-storage sessions route these requests to the elected storage owner, and storage listings only aggregate peers in the same shared-storage scope.
#15495 1dba24a Thanks @penalosa! - Prevent short-lived Miniflare instances from hanging during disposal
Wait for the development registry's filesystem watcher to finish initialising before runtime startup completes, ensuring the watcher can always be closed cleanly.
#15469 d40a634 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260831.1 | ^5.20260902.1 |
| workerd | 1.20260831.1 | 1.20260902.1 |
#15481 7c1b2a6 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260902.1 | ^5.20260903.1 |
| workerd | 1.20260902.1 | 1.20260903.1 |
You can now narrow an instance listing to a creation-time window:
#15353 87a7acf Thanks @pombosilva! - Add --date-start and --date-end filters to wrangler workflows instances list
You can now narrow an instance listing to a creation-time window:
wrangler workflows instances list my-workflow --date-start 2026-01-01 --date-end 2026-01-31
Either flag can be used independently. Both accept an ISO 8601 date or timestamp and are normalised to UTC before being sent, so a date-only value such as 2026-01-01 works as well as a full 2026-01-01T13:00:00Z. The bounds are inclusive and compose with the existing --status filter.
#15436 200780f Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260828.1 | ^5.20260831.1 |
| workerd | 1.20260828.1 | 1.20260831.1 |
#15406 b3f2628 Thanks @james-elicx! - Reduce the installed bundle sizes of Wrangler and Miniflare
Wrangler now resolves bundled workspace dependencies from source during monorepo builds so unused exports can be removed. Miniflare, its shared CLI and container dependencies now use granular @cloudflare/workers-utils entry points instead of loading the package barrel, reducing the raw Wrangler and Miniflare artifacts by 6.16 MiB (31.4%) and 1.06 MiB (22.9%) respectively without changing runtime behavior or installed dependencies.
Add an Email group with Routing and Sending views for inspecting messages received by a Worker's email() handler and messages sent through its send_em
#15337 b23de74 Thanks @tpmmorris! - Add email inspection and testing to Local Explorer
Add an Email group with Routing and Sending views for inspecting messages received by a Worker's email() handler and messages sent through its send_email bindings. Detail views show message content, metadata, attachments, and handler activity including forwarding, replies, rejection, and unhandled messages.
Add a test-email composer that delivers custom text, HTML, headers, and attachments directly to the selected Worker's email() handler during local development.
#15305 015550a Thanks @Monark-Arkmon! - Support env.IMAGES.hosted.createDirectUpload() in local development. Creates a draft image and returns an uploadURL served by a new local endpoint that accepts the completed upload as multipart/form-data (field name file). Matches production's validation (expiresIn bounds of 120–21600 seconds, rejecting UUID custom IDs) and single-use/expiry semantics: completing an unknown or already-used upload link returns 404/409, and an expired link returns 410.
#15305 015550a Thanks @Monark-Arkmon! - Support the filter.metadata option on env.IMAGES.hosted.list() in local development, matching the metadata filtering behaviour of the production Images binding. Filters support the eq (implicit for bare values), in, gt, gte, lt, and lte operators, dot-notation nested field paths, and AND logic across multiple fields.
#15305 015550a Thanks @Monark-Arkmon! - Support env.IMAGES.hosted.image(id).signedUrl() in local development. A fixed local-dev signing secret is used to generate and verify signed delivery URLs, so images uploaded with requireSignedURLs: true can only be fetched from the local image delivery endpoint with a valid, unexpired signature — matching the production Images binding's signed URL behaviour end-to-end.
#15373 3650d29 Thanks @jamesopstad! - Rename Worker target fields from workerName to worker
The experimental @cloudflare/config and Miniflare configuration APIs now use worker consistently for Worker, Durable Object, Workflow, dispatch namespace, and tail consumer targets.
#15383 eb01850 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260826.1 | ^5.20260827.1 |
| workerd | 1.20260826.1 | 1.20260827.1 |
#15393 e1df91a Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260827.1 | ^5.20260828.1 |
| workerd | 1.20260827.1 | 1.20260828.1 |
#15337 b23de74 Thanks @tpmmorris! - Validate custom headers sent through the Local Explorer test-email endpoint
Reject header names and values that cannot be safely encoded. Multiline values remain supported and are folded into valid MIME continuation lines.
The following dependency versions have been updated:
#15367 412c79e Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260825.1 | ^5.20260826.1 |
| workerd | 1.20260825.1 | 1.20260826.1 |
Builder replies now generate the recipient, threading headers, and a production-style Message-ID automatically. Raw EmailMessage replies also use a ge
#15064 693ca29 Thanks @tpmmorris! - Support EmailReplyMessageBuilder when replying from local email handlers
Builder replies now generate the recipient, threading headers, and a production-style Message-ID automatically. Raw EmailMessage replies also use a generated production-style Message-ID; user-provided Message-ID headers are rejected in favor of the generated ID.
#15064 693ca29 Thanks @tpmmorris! - Include a chronological list of handler events in email test harness results, so programmatic local email tests can assert the order in which messages are received, forwarded, replied to, or rejected.
const result = await server.getWorker().email({
from: "sender@example.com",
to: "inbox@example.com",
raw: [
"From: Sender <sender@example.com>",
"To: Inbox <inbox@example.com>",
"Message-ID: <test@example.com>",
"Subject: Test email",
"",
"Hello from the test harness",
].join("\r\n"),
});
expect(result.events).toEqual([
{ type: "received", timestamp: expect.any(String) },
{
type: "forward",
timestamp: expect.any(String),
messageId: expect.any(String),
},
{
type: "reply",
timestamp: expect.any(String),
messageId: expect.any(String),
},
]);#15187 37ed753 Thanks @penalosa! - Support Images data in experimental shared local storage
#15188 f76b68e Thanks @penalosa! - Support Stream in experimental shared local storage
#15134 c66d2d5 Thanks @gpanders! - Enable FUSE-capable local container development
Miniflare now automatically passes the Docker privileges needed for FUSE to local Durable Object containers when using local rootless Docker on Linux with /dev/fuse available, or a local Docker engine on macOS or through WSL where Linux containers run in a VM. This applies to Wrangler, the Cloudflare Vite plugin, and direct Miniflare use.
#15064 693ca29 Thanks @tpmmorris! - Capture locally sent and received emails, along with forwarding and reply activity and metadata, for inspection through the Local Explorer email API.
Miniflare now captures locally sent and received emails, including forwarding, reply, rejection, and exception activity. The following endpoints are available below /cdn-cgi/local/explorer/api while wrangler dev is running:
POST /local/email/routing/send?worker=<name> sends a test email to a Worker's email() handler.GET /local/email/routing?worker=<name> lists emails received by a Worker.GET /local/email/routing?email_id=<message-id>&worker=<name> returns a received email and its handler activity.GET /local/email/sending?worker=<name> lists emails sent through a Worker's send_email bindings.GET /local/email/sending?email_id=<message-id>&worker=<name> returns a sent email.For example, send and then inspect a test email against a Worker named my-worker:
curl -X POST \
"http://localhost:8787/cdn-cgi/local/explorer/api/local/email/routing/send?worker=my-worker" \
-H "Content-Type: application/json" \
--data '{
"from": "sender@example.com",
"to": ["inbox@example.com"],
"subject": "Local test",
"text": "Hello from Local Explorer"
}'
curl \
"http://localhost:8787/cdn-cgi/local/explorer/api/local/email/routing?worker=my-worker"List endpoints support per_page and opaque cursor query parameters. File paths logged by the send_email binding are asynchronous debugging artifacts and should not be used to synchronize after send() resolves. Email handler exceptions are logged when structured local delivery reports an exception outcome.
When email content exceeds the local storage row budget of approximately 2 MB, the email is delivered in full but the Local Explorer capture is truncated to fit. Detail responses identify each truncated sent email, received email, or reply in the top-level messages array with warning code 10604; for example:
{
"messages": [
{
"code": 10604,
"message": "Displayed received email content was truncated during local capture. The complete message was still delivered to the Worker."
}
]
}#15169 dd5148d Thanks @penalosa! - Add experimental shared local storage, letting several Miniflare instances read and write one set of local resources
Each instance previously kept its own copy of local state, so two dev sessions pointed at the same KV namespace or D1 database could not see each other's writes. Instances that opt in now elect a single storage owner through the dev registry and route storage through it, so resources with the same ID resolve to the same data.
Opt in with unsafeEnableSharedStorage, which requires three paths to be set:
new Miniflare({
unsafeEnableSharedStorage: true,
// Shared between instances: resources that participate in sharing live here
resourcePersistencePath: "/path/to/shared/state",
// Per project: resources that cannot be shared keep their own state here
isolatedResourcePersistencePath: "/path/to/project/state",
// Instances elect the storage owner through the dev registry
unsafeDevRegistryPath: "/path/to/registry",
// ...
});KV, D1, R2, Rate Limits, and Secrets Store participate in sharing. Cache, Durable Objects, Workflows, observability, and Hello World storage do not yet, and stay instance-local under isolatedResourcePersistencePath, keeping their state across restarts without concurrent access to the shared root.
This is experimental and the unsafe-prefixed options may change without a major version bump.
#15318 82d11fc Thanks @jamesopstad! - Consolidate development-only binding configuration under dev
This experimental configuration now uses dev.remote for remote bindings and dev.connectionString for Hyperdrive. Miniflare's v5 binding configuration follows the same shape, and R2's local S3 credentials now share the dev object.
#15341 aa54b49 Thanks @jamesopstad! - Remove unsupported remote configuration from Workflow bindings
Miniflare now rejects dev.remote on Workflow bindings and no longer exposes or converts the legacy Workflow remoteProxyConnectionString option. Workflows always use the local simulator.
#15294 4a67a28 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260820.1 | ^5.20260821.1 |
| workerd | 1.20260820.1 | 1.20260821.1 |
#15328 2d78137 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260821.1 | ^5.20260823.1 |
| workerd | 1.20260821.1 | 1.20260824.1 |
#15346 04e8564 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260823.1 | ^5.20260825.1 |
| workerd | 1.20260824.1 | 1.20260825.1 |
#15064 693ca29 Thanks @tpmmorris! - Generate and use production-style Message-IDs for local email artifacts
Locally sent emails and replies now use generated Message-IDs - which are 36 alphanumeric characters - consistently in returned results, raw MIME headers, Local Explorer records, and stored artifact filenames. User-provided Message-ID headers are replaced by the generated ID.
For example, sending an email from sender@example.com may return <AbCdEfGhIjKlMnOpQrStUvWxYz0123456789@example.com>. The raw email uses that same value for its Message-ID header, the Local Explorer exposes the same ID, and the stored artifact is named AbCdEfGhIjKlMnOpQrStUvWxYz0123456789@example.com.eml.
Similarly, a reply containing Message-ID: <custom@example.com> is stored and returned with a newly generated ID instead. This mirrors production behavior and prevents the supplied ID from becoming the local artifact key.
#15316 74de3ab Thanks @dexvdev! - Restore cross-process service bindings after a machine wakes from sleep
Workers running in separate wrangler dev or Vite dev sessions now reconnect automatically after the machine wakes. Previously, service bindings could return Worker "<name>" not found until the serving process reloaded or restarted.
#15242 0cb8690 Thanks @aesopfrom0! - Shut down workerd when Miniflare is terminated with SIGHUP
On SIGHUP, Miniflare now stops workerd and removes its temporary directory instead of leaving them behind. Previously only SIGINT and SIGTERM were handled, so tools that embed Miniflare, such as @cloudflare/vitest-pool-workers and @cloudflare/vite-plugin, could leave a stray process and directory behind on each run.
This internal assets testing option is no longer supported.
#15130 99a1f49 Thanks @emily-shen! - Remove the deprecated hasAssetsAndIsVitest option
This internal assets testing option is no longer supported.
#15130 99a1f49 Thanks @emily-shen! - Change R2 local S3 credentials configuration
R2 bindings now use localDev.experimentalS3Credentials instead of s3Credentials for local S3 endpoint credentials.
#14995 59872c4 Thanks @ThomasRubini! - Add connect trigger for raw sockets
You can now configure a Worker to receive raw socket connections during wrangler dev, delivered directly to the Worker's connect(socket, env, ctx) handler:
{
"connect": [{ "protocol": "tcp", "port": 5432 }]
}Each entry opens a listening socket on 127.0.0.1 (or the given address) that forwards incoming connections straight to the Worker, bypassing the local dev HTTP entry point. This requires the experimental compatibility flag. Only "tcp" is supported at the moment.
@cloudflare/config also supports declaring this trigger via triggers.connect(...), which lowers to the connect field above:
import { defineWorker, triggers } from "@cloudflare/config";
export default defineWorker({
triggers: [
triggers.connect({ protocol: "tcp", port: 5432, address: "127.0.0.1" }),
],
});#14735 30c2d47 Thanks @vaishnav-mk! - Add individual and batch Workflow instance deletion to the runtime and SDK.
WorkflowInstance.delete() deletes one instance. Self-deletion stops the current execution.env.MY_WORKFLOW.deleteBatch(instanceIds) deletes up to 100 instances and returns { deleted, errors } per input position.wrangler workflows instances delete <name> [id..] deletes instances remotely or with --local; IDs can also come from a JSON array passed with --filename, with a combined limit of 100.#15130 99a1f49 Thanks @emily-shen! - Default local Analytics Engine dataset names in Miniflare
Analytics Engine dataset bindings without an explicit name now fallback to the worker and binding name as a default.
#15260 5ae9d5b Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260815.1 | ^5.20260816.1 |
| workerd | 1.20260815.1 | 1.20260816.1 |
#15264 4b52975 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260816.1 | ^5.20260819.1 |
| workerd | 1.20260816.1 | 1.20260819.1 |
#15277 ce9b151 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260819.1 | ^5.20260820.1 |
| workerd | 1.20260819.1 | 1.20260820.1 |
If the Chrome download for a browser binding was interrupted — a cancelled dev session, a killed test run, a machine going to sleep — the next launch
#15206 1277a72 Thanks @petebacondarwin! - Recover automatically from a partially downloaded Chrome install for the Browser Run binding
If the Chrome download for a browser binding was interrupted — a cancelled dev session, a killed test run, a machine going to sleep — the next launch could fail indefinitely with Failed to launch the browser process!, usually alongside a message about being unable to load resources.pak. @puppeteer/browsers treats an install as present as soon as the executable exists, and the Chrome archives extract alphabetically, so the executable is written long before the resources it needs. Every subsequent launch then reused the half-written directory, and the only way out was deleting the Chrome cache by hand.
Miniflare now detects this: an install that Chrome has never successfully started from is cleared and re-downloaded on a failed launch, rather than reused forever. Overlapping launches also share a single download instead of racing to populate the same directory.
#15231 4f922dc Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260811.1 | ^5.20260814.1 |
| workerd | 1.20260811.1 | 1.20260814.1 |
#15248 4d74b8d Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260814.1 | ^5.20260815.1 |
| workerd | 1.20260814.1 | 1.20260815.1 |
#15143 2e0c962 Thanks @teamleaderleo! - Prevent workerd from remaining running during Miniflare shutdown when browser or proxy cleanup is slow or fails.
You can now configure a mock Cloudflare Access identity in wrangler.json so that ctx.access.getIdentity() returns it during local development.
#15113 b8fd112 Thanks @BSFishy! - Add local dev simulation for Cloudflare Access ctx.access.getIdentity()
You can now configure a mock Cloudflare Access identity in wrangler.json so that ctx.access.getIdentity() returns it during local development.
// wrangler.json
{
"access": {
"dev": {
"aud": "my-app-aud-tag",
"identity": {
"email": "user@example.com",
"name": "Test User"
}
}
}
}
The updated @cloudflare/workers-types now requires delete() on workflow instances and deleteBatch() on the workflow binding. These methods are now imp
#15123 d0c976c Thanks @dependabot! - Add local support for WorkflowInstance.delete() and Workflow.deleteBatch()
The updated @cloudflare/workers-types now requires delete() on workflow instances and deleteBatch() on the workflow binding. These methods are now implemented in the local workflows simulator so that local dev and tests match the production API.
#15123 d0c976c Thanks @dependabot! - Detect Node.js compatibility from the compatibility date, now that nodejs_compat is enabled by default
As of compatibility date 2026-08-04, workerd enables the nodejs_compat and nodejs_compat_v2 compatibility flags by default. Previously these tools only treated Node.js compatibility as enabled when one of those flags was listed explicitly, so a Worker on a compatibility date of 2026-08-04 or later without the flag would get Node.js APIs from the runtime but no Node.js polyfills from the bundler, and process.env could be substituted with an empty object at build time. They now resolve these flags the same way workerd does, and honour no_nodejs_compat to opt out.
To keep Node.js compatibility switched off on a newer compatibility date, specify both no_nodejs_compat and no_nodejs_compat_v2, since each flag has its own default.
@cloudflare/vitest-pool-workers needs nodejs_compat_v2 for its own test runner, so it continues to override a project that opts out of it. On a compatibility date that enables the flag anyway, it now drops the opt-out rather than adding the flag back, which workerd would reject — previously this stopped such a project from running any tests at all.
wrangler types also no longer attributes its @types/node suggestion to "the nodejs_compat flag", which it can now make for Workers that do not set the flag at all.
#15123 d0c976c Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260804.1 | ^5.20260811.1 |
| workerd | 1.20260804.1 | 1.20260811.1 |
#15148 0b82b15 Thanks @jamesopstad! - Ignore a nodejs_compat compatibility flag that the compatibility date already enables
workerd rejects a compatibility flag that its compatibility date enables by default, so a Worker configured with both a compatibility date of 2026-08-04 or later and nodejs_compat failed to start locally with "The compatibility flag nodejs_compat became the default as of 2026-08-04 so does not need to be specified anymore".
The redundant nodejs_compat and nodejs_compat_v2 flags are now dropped when starting the runtime, which has no effect on the resulting Worker because the compatibility date enables both anyway. no_nodejs_compat and no_nodejs_compat_v2 still switch Node.js compatibility off, and a flag specified alongside its own opt-out is left alone so that workerd still reports those as contradictory.
#15131 90dd5e5 Thanks @vicb! - Bump capnp-es to 0.0.15.
Also re-generate the types for the latest .capnp files
When a Worker's tail consumer runs in a separate local dev session and that session becomes unreachable, the failure to deliver tail events was discar
#14993 c7aede7 Thanks @petebacondarwin! - Report failures to forward tail events between local dev sessions
When a Worker's tail consumer runs in a separate local dev session and that session becomes unreachable, the failure to deliver tail events was discarded silently. It is now reported as a warning.
Miniflare no longer supports deprecated beta D1 instances created before wrangler@3.3.0.
#14994 2194f88 Thanks @emily-shen! - Replace Miniflare's options API with Cloudflare config-based worker options
new Miniflare() and setOptions() now require a workers array of worker entries. Binding, service, tail, remote, asset, workflow, unsafe binding, and other worker configuration now follows the schemas in packages/miniflare/src/config/schema.ts.
The previous flat options shape is no longer accepted directly. Existing v4-shaped options can be migrated with convertV4MiniflareOptions().
#14994 2194f88 Thanks @emily-shen! - Change the Miniflare plugin API
Plugins now receive parsed Miniflare worker and instance config instead of per-plugin option slices. Per-plugin option schema exports have been removed; unsafe plugin authors should read bindings, exports, and triggers from the parsed config passed to plugin hooks.
#14994 2194f88 Thanks @emily-shen! - Remove automatic module graph discovery
Miniflare no longer discovers Worker modules from modules: true and modulesRules. Module workers must provide their module graph through the config manifest. Existing v4-shaped options can be migrated with convertV4MiniflareOptions(), but modulesRules cannot be converted without losing behavior.
#14994 2194f88 Thanks @emily-shen! - Remove internal or redundant options from Miniflare's config
Miniflare no longer accepts service designator objects such as { network }, { external }, and { disk } on outboundService, tails, or streamingTails.
Miniflare also no longer supports unsafeExcludeFromObservability, which has been dropped in favour of unsafeRegisterWorker.
#14994 2194f88 Thanks @emily-shen! - Remove support for legacy alpha D1 (__D1_BETA__) bindings
Miniflare no longer supports deprecated beta D1 instances created before wrangler@3.3.0.
#14994 2194f88 Thanks @emily-shen! - Add convertV4MiniflareOptions for migrating Miniflare v4 options
You can now convert v4-shaped Miniflare options to the config-based workers shape before creating or updating a Miniflare instance. Some v4 options cannot be converted without losing behavior and will throw an error instead.
#15072 6dbd192 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260801.1 | ^5.20260804.1 |
| workerd | 1.20260801.1 | 1.20260804.1 |
Set unsafeRegisterWorker to false to prevent a Miniflare worker from being advertised in the dev registry. Workers continue to be registered by defaul
#15040 99eb50c Thanks @edmundhung! - Add an option to disable dev registry registration
Set unsafeRegisterWorker to false to prevent a Miniflare worker from being advertised in the dev registry. Workers continue to be registered by default.
#15037 b4f0c97 Thanks @petebacondarwin! - Stop deleting and recreating every dev registry entry on each config update
Applying options rewrote this instance's dev registry entries by removing them and putting them straight back. Other dev sessions find Workers by watching that directory, so each update briefly looked to them like every Worker in the session had gone away — and a session that had already resolved one of those Workers could be left acting on that, up to and including tearing down a binding to a Worker that never actually stopped running.
Entries are now reconciled instead: Workers that are still present are updated in place, and only the ones that have genuinely gone are removed. Switching to a different registry path still clears the entries from the directory being left behind.
#15013 8cf78c8 Thanks @dario-piotrowicz! - Update undici from 7.28.0 to 7.29.0
#15015 a60ff4d Thanks @nickpatt! - Cut the per-request cost of local observability capture
Every tail event was written to the trace store as its own Durable Object call, so a request paid two or three round-trips per span. On a module-heavy app under the Vite plugin that dominated dev request latency. Rows are now buffered and written in batches, taking a request from roughly thirty calls to three.
Work in progress still shows up as it happens: the root span is written immediately, console logs and exceptions as they arrive, and a span's completion is written on the next event once 100ms has passed. An invocation that goes completely quiet writes nothing further until it ends, since the flush is driven by tail events rather than a timer.
The Vite plugin's own router, asset and proxy workers are also no longer captured. Their traces were noise the Observability views already hid, and skipping them cuts the spans recorded per request — a side benefit being that a trace's root is now your Worker rather than __router-worker__.
The following dependency versions have been updated:
#14984 9c74538 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260730.1 | ^5.20260731.1 |
| workerd | 1.20260730.1 | 1.20260731.1 |
#15012 0d33cb8 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260731.1 | ^5.20260801.1 |
| workerd | 1.20260731.1 | 1.20260801.1 |
#14968 a88d169 Thanks @petebacondarwin! - Fix local rate limiting being disabled entirely when bindings share a namespace_id but use different periods
The emulated Ratelimit binding tracked one counter per key per namespace, ignoring the period. Two bindings pointing at the same namespace_id with different simple.period values therefore overwrote each other's counter on every call — each one seeing a window it did not recognise, and so resetting the count to zero — with the result that neither binding ever limited anything:
{
"ratelimits": [
{
"name": "BURST",
"namespace_id": "1001",
"simple": { "limit": 20, "period": 10 }
},
{
"name": "SUSTAINED",
"namespace_id": "1001",
"simple": { "limit": 50, "period": 60 }
}
]
}
Counters are now tracked per period, matching production, where a counter is identified by a bucket index and bucket start timestamp that are both derived from the period. Bindings that share a namespace_id and a period still share a counter for a given key.
#14968 a88d169 Thanks @petebacondarwin! - Fix local rate limit counters silently resetting after ~10s of inactivity
The emulated Ratelimit binding kept its counters on the JS heap of an internal Durable Object. workerd evicts idle Durable Objects after around 10 seconds, taking the counters with them, so in wrangler dev you could hit your Worker, pause to look at something, and find your limit had silently reset part way through the window.
Counters now live in the Durable Object's storage, which survives eviction. They are still cleared by deleteAllDurableObjects(), so reset() from @cloudflare/vitest-pool-workers continues to reset rate limit state between tests, exactly as it does for KV, R2 and D1. Counters are now also written to the persistence directory, so they survive a wrangler dev restart within the same window.
#14989 daf65f2 Thanks @petebacondarwin! - Surface the full runtime crash report when workerd crashes, and warn when it is restarted
When workerd crashed, the banner (e.g. *** std::terminate() called with no exception) was reported without its stack trace, because the stack trace was being filtered out along with the ordinary hex-stack noise workerd emits. The crash was therefore impossible to diagnose. The stack: line and the missing-$LLVM_SYMBOLIZER notice that follow a fatal crash banner are now kept, and the whole report is logged at error level.
Miniflare also recovers from workerd crashes by restarting the runtime, but did so silently, which made a crash look like an unexplained dev server restart. It now warns, including a count so that a repeatedly-crashing runtime is distinguishable from a one-off.
/cdn-cgi/mf/scheduled → removed (was already deprecated)
#14586 5a56dda Thanks @emily-shen! - Consolidate persistence and temporary directory options
The per-resource persistence options (kvPersist, r2Persist, d1Persist, cachePersist, durableObjectsPersist, workflowsPersist, secretsStorePersist, analyticsEngineDatasetsPersist, streamPersist, imagesPersist, and helloWorldPersist) have been removed. The Miniflare.unsafeGetPersistPaths() method, which provided the per-resource persistence paths, has also been removed as they can now be stably inferred from the base path.
For consistency and clarity, defaultPersistRoot and defaultProjectTmpPath have been renamed to resourcePersistencePath and resourceTmpPath, respectively.
For example:
new Miniflare({
resourcePersistencePath: ".wrangler/state/v3",
resourceTmpPath: ".wrangler/tmp",
});
When resourcePersistencePath is set, each resource persists to a subdirectory named after its plugin (e.g. .wrangler/state/v3/kv). When it is omitted, resources are ephemeral and their data is cleared on dispose.
#14586 5a56dda Thanks @emily-shen! - Remove the cacheWarnUsage option
The cacheWarnUsage Worker option, which logged a warning when cache operations were used, has been removed.
#14586 5a56dda Thanks @emily-shen! - Remove the fetchMock option and createFetchMock export
#14586 5a56dda Thanks @emily-shen! - Remove the httpsKeyPath and httpsCertPath options
The httpsKeyPath and httpsCertPath options have been removed. To use a custom certificate, read the files and pass their contents via the existing httpsKey and httpsCert options.
#14586 5a56dda Thanks @emily-shen! - Drop /cdn-cgi/mf/reload live reload endpoint and liveReload option
The built-in live reload mechanism has been removed from Miniflare. This included a WebSocket endpoint at /cdn-cgi/mf/reload, the liveReload option, and the automatic injection of a live reload <script> tag into HTML responses. For context, Wrangler and the Vite plugin both implement their own independent live reload mechanisms.
#14586 5a56dda Thanks @emily-shen! - Drop miniflare v2 storage migration
The migrateDatabase() helper that migrated KV, R2, and D1 SQLite databases from the miniflare v2/early-v3 storage layout to the current Durable Object-based layout has been removed. This migration path was introduced in 2023 and is no longer needed.
#14586 5a56dda Thanks @emily-shen! - Only support structured workerd logs
The handleRuntimeStdio option (for handling the raw workerd stdout/stderr streams) and the structuredWorkerdLogs option (for toggling structured workerd logs) have been removed. Structured logging is now always enabled.
To receive workerd's output, use handleStructuredLogs, which is passed parsed structured log entries. When no handleStructuredLogs handler is provided, logs are written to the console by default (warn/error to stderr, everything else to stdout).
#14586 5a56dda Thanks @emily-shen! - Drop the unsafeStickyBlobs option
This prevented blob files from being deleted when overwriting or deleting keys, and only existed to support the Durable Object isolated storage feature in @cloudflare/vitest-pool-workers, which was removed in 0.13.0. Blobs are now always cleaned up as expected.
#14586 5a56dda Thanks @emily-shen! - Remove the wrappedBindings option
#14586 5a56dda Thanks @emily-shen! - Move containerEngine from a per-worker option to a top-level option
containerEngine is now a top-level Miniflare option rather than a per-worker option, reflecting that it configures a single container engine for the whole Miniflare instance.
new Miniflare({
containerEngine: "unix:///var/run/docker.sock",
workers: [{ name: "my-worker", script: "..." }],
});
Previously it was set inside each worker's options.
#14586 5a56dda Thanks @emily-shen! - Move formatZodError from miniflare to @cloudflare/workers-utils
The formatZodError and _forceColour helpers are no longer exported from miniflare; they are now exported from @cloudflare/workers-utils.
#14586 5a56dda Thanks @emily-shen! - Remap local testing paths to avoid collision with production /cdn-cgi routes
All miniflare-internal endpoints have moved to more consistent paths. Paths that need to remain reachable over tunnels now live outside /cdn-cgi/:
/cdn-cgi/platform-proxy → /cdn-cgi/local/platform-proxy/cdn-cgi/handler/scheduled → /cdn-cgi/local/scheduled/cdn-cgi/handler/email → /cdn-cgi/local/email/cdn-cgi/explorer/* → /cdn-cgi/local/explorer/*/cdn-cgi/mf/scheduled → removed (was already deprecated)/cdn-cgi/mf/stream/* → /__cf_local/stream/*/cdn-cgi/mf/imagedelivery/* → /__cf_local/imagedelivery/*Wrangler and the Vite plugin will add transparent path rewrites so the old paths continue to work for users of those tools.
#14586 5a56dda Thanks @emily-shen! - Remove deprecated maxRetires typo alias in Queue consumer options
The maxRetires option (a typo of maxRetries) has been removed from QueueConsumerOptionsSchema. Use maxRetries instead.
#14586 5a56dda Thanks @emily-shen! - Remove dummy CLI binary
The miniflare bin entry and bootstrap.js stub that printed a "use npx wrangler dev" error have been removed. This stub has been present since miniflare v3 and is no longer needed.
#14586 5a56dda Thanks @emily-shen! - Remove deprecated supportedCompatibilityDate export
#14586 5a56dda Thanks @emily-shen! - Rename the cache Worker option to cacheAPI
The boolean option controlling whether the Cache API caches anything has been renamed from cache to cacheAPI. This is to distinguish it from Workers Cache.
#14586 5a56dda Thanks @emily-shen! - Upgrade to zod v4
Miniflare's exported schemas now use zod v4.
The /cdn-cgi/handler/email endpoint now accepts ?format=json to return the email handler result as JSON, including its outcome, rejection reason, forw
#14685 01d7020 Thanks @edmundhung! - Add JSON output to /cdn-cgi/handler/email
The /cdn-cgi/handler/email endpoint now accepts ?format=json to return the email handler result as JSON, including its outcome, rejection reason, forwarded messages, and replies. Requests without format=json still return the existing text outcome for backward compatibility.
#14929 48f0c6c Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260722.1 | ^5.20260730.1 |
| workerd | 1.20260722.1 | 1.20260730.1 |
#14810 d7f38c3 Thanks @allocsys! - Fix the local Images binding transform (env.IMAGES.input(...).transform(...)) ignoring the fit, gravity, and background options. Previously, local dev always letterboxed transformed images with black bars regardless of the options passed in. Local dev now respects fit, gravity, and background, matching production Images binding behavior.
#14850 5c25cfe Thanks @exKAZUu! - Disable the keep-alive timeout on the loopback server
The loopback server (which serves custom service bindings, @cloudflare/vite-plugin's module transport, and other workerd → Node callbacks) used Node's default server.keepAliveTimeout of 5 seconds. workerd pools and reuses connections to the loopback server, so Node closing an idle pooled socket raced with workerd sending the next request on it, making that request fail with Network connection lost. The failure is probabilistic and load-dependent; under @cloudflare/vite-plugin with a large SSR module graph and a cold optimizer cache (thousands of fetchModule calls with multi-second idle gaps between bursts), it broke most dev sessions. Disable the idle keep-alive timeout on the loopback server, mirroring the undici pools used for dispatch in the opposite direction.
#14914 1f61001 Thanks @nickpatt! - Capture Workflows invocations in local observability
When local observability is enabled, the Workflows engine service is now attached to the trace collector (like every user worker), so workflow runs show up in the Local Explorer's Observability view attributed to the workflow. Previously the engine ran outside the per-user-worker tail wiring, so workflow invocations left no traces, spans, or logs in the local store.
The generated workerd config already supports v8Flags, but Miniflare never populated it, so the runtime always ran with V8's default heap limit (~1.4
#14702 e426cb9 Thanks @Sipixer! - Support passing V8 flags to workerd via the MINIFLARE_WORKERD_V8_FLAGS environment variable
The generated workerd config already supports v8Flags, but Miniflare never populated it, so the runtime always ran with V8's default heap limit (~1.4 GB). Large dev applications (e.g. big SSR module graphs under @cloudflare/vite-plugin, where each server-file edit grows the runner isolate's heap) can reach that limit, at which point workerd aborts with V8 fatal error; location = Reached heap limit and every subsequent dispatchFetch() fails with fetch failed until the dev server is manually restarted.
Setting e.g. MINIFLARE_WORKERD_V8_FLAGS="--max-old-space-size=4096" raises the limit and keeps long dev sessions alive. The variable follows the same space-separated format as MINIFLARE_WORKERD_AUTOGATES.
#14280 465c0fb Thanks @tahmid-23! - Add a local S3-compatible API for R2 buckets at /cdn-cgi/local/r2/s3/<bucket-id>, where <bucket-id> is the ID the bucket is configured with in the r2Buckets option
Buckets configured with s3Credentials: { accessKeyId, secretAccessKey } in r2Buckets are served over an S3-compatible HTTP API, authenticated with AWS Signature Version 4 (both Authorization header and presigned URL query authentication). Supported operations: GetObject, HeadObject, PutObject, CopyObject, DeleteObject, DeleteObjects, ListObjects, ListObjectsV2, HeadBucket, ListBuckets, CreateMultipartUpload, UploadPart, UploadPartCopy, CompleteMultipartUpload, and AbortMultipartUpload. Status codes, error responses, and unsupported-header screening mirror R2's S3 endpoint, including its static responses for bucket-configuration reads and its named errors for unimplemented operations.
#14712 6e0bf6e Thanks @mack-erel! - Support connect() on remote VPC Network and VPC Service bindings in local development
Remote VPC Network and VPC Service bindings previously only supported HTTP and JSRPC, so calling binding.connect(address) against a private TCP service (for example a database) failed in local dev with Incoming CONNECT on a worker not supported. Raw TCP connections through remote VPC Network and VPC Service bindings now work in local development.
This feature is experimental. Existing HTTP and JSRPC usage of remote VPC Network and VPC Service bindings is unaffected, and no new configuration is required.
#14784 1035f74 Thanks @ATKasem! - Fix getWithMetadata dropping metadata for falsy KV values
KVNamespace.getWithMetadata returned null metadata whenever the stored value was falsy — an empty string or "0" — because the metadata branch was guarded by a truthiness check on the value. The guard now checks for null explicitly, so metadata is preserved for empty-string and "0" values while genuinely missing keys still return null.
#14864 3a22ae5 Thanks @Hashim1999164! - Hide the workerd console window on Windows when the parent process has no console. Spawning workerd without windowsHide: true caused Windows Terminal to open a visible, focus-stealing window for background or detached parents (for example Astro's astro dev --background).
wrangler dev and the Vite plugin now capture a trace for every local Worker invocation - spans, logs, and console.* output, including requests that cr
#14633 3203b5d Thanks @nickpatt! - Add local-dev observability
wrangler dev and the Vite plugin now capture a trace for every local Worker invocation - spans, logs, and console.* output, including requests that cross worker or Durable Object boundaries.
You can explore this data two ways:
/cdn-cgi/explorer/api/local/observability/query, discoverable via the Local Explorer's OpenAPI document, so coding agents and tools can query the same spans and logs tables.While this is in testing it's off by default; set X_LOCAL_OBSERVABILITY=true to turn it on. It will be on by default in the public release.
#14796 c38a2c3 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260721.1 | ^5.20260722.1 |
| workerd | 1.20260721.1 | 1.20260722.1 |
#14772 c079ba3 Thanks @chinesepowered! - Fix incorrect byte limit reported in the local Queues batch-size error
When a queue batch exceeded the maximum batch byte size in local dev, the thrown PayloadTooLargeError hardcoded the limit as 256000, even though the value actually enforced is 288000 bytes ((256 + 32) * 1000). The message now interpolates the real limit, consistent with the other Queue limit errors in the same file.
#14493 95b026e Thanks @petebacondarwin! - Update sharp to 0.35.2
sharp 0.35 removes its install lifecycle script, so package managers that block dependency build scripts by default (such as pnpm 11+) no longer require an explicit build approval for it when installing miniflare/wrangler. The local Images binding keeps using the same prebuilt sharp binaries, so image transforms in local dev are unaffected.
This release also reworked sharp's FormatEnum types: libvips reports AVIF inputs under the heif container. The local Images binding /info endpoint and the cf.image transform path now correctly report AVIF as image/avif instead of treating it as an unsupported/unknown type.
#14792 c4bacec Thanks @matthewp! - Recover local development after the Workers runtime crashes
Previously, an unexpected workerd crash left Miniflare running but unable to serve subsequent requests. Miniflare now restarts workerd after post-startup crashes, while continuing to surface startup crashes as fatal errors.
The Cloudflare Vite plugin also restarts the Vite development server after workerd recovers so its environments, hot channels, and module runners are recreated.
Steps configured with sensitive: "output" now have their output redacted to [REDACTED] in step logs and step-output responses when running Workflows l
#14742 34430b3 Thanks @pombosilva! - Add support for redacting sensitive Workflows step output in local dev.
Steps configured with sensitive: "output" now have their output redacted to [REDACTED] in step logs and step-output responses when running Workflows locally, matching production behavior. The real value is still passed to downstream steps, and step errors are never redacted.
#14715 42af66d Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260714.1 | ^5.20260721.1 |
| workerd | 1.20260714.1 | 1.20260721.1 |
#14766 4815711 Thanks @gianghungtien! - Report the Worker's error for HEAD requests instead of an internal JSON parse error
A Worker that threw on a HEAD request (for example curl -I) logged SyntaxError: Unexpected end of JSON input from miniflare's internals rather than the actual error, and dispatchFetch() rejected with that same misleading error. workerd drops response bodies for HEAD requests, so the serialised error never reached the code that revives it.
The error is now also carried in a header, which survives HEAD, so the original message and source-mapped stack are reported for every method. When no payload is available the reporting degrades to a plain error rather than surfacing a parse failure.
The runtime catches handler exceptions to build the 500 response, so they never reach the inspector — the one place an uncaught exception exists as a
#14562 9f04a7e Thanks @martijnwalraven! - Add a handleUncaughtError shared option that receives uncaught Worker exceptions
The runtime catches handler exceptions to build the 500 response, so they never reach the inspector — the one place an uncaught exception exists as a structured value in Node is the pretty-error path, where the error report from the Worker is revived into a source-mapped Error. Embedders can now pass handleUncaughtError: (error: Error) => void to observe that revived error programmatically; logging behavior is unchanged.
The hook fires only where the pretty-error path does: requests reaching the Worker through the entry socket (a browser or another HTTP client against the dev server). dispatchFetch() is unaffected — it always sets MF-Disable-Pretty-Error, and the entry worker then propagates the exception by rejecting the returned promise instead, so dispatchFetch() callers already receive the error directly and the hook is not invoked.
#14706 cb6c3f9 Thanks @edmundhung! - Add Durable Object storage access to createTestHarness()
You can now execute SQL against a SQLite-backed Durable Object to seed or assert the storage state.
const server = createTestHarness({
workers: [{ configPath: "./wrangler.json" }],
});
await server.listen();
const worker = server.getWorker();
const storage = await worker.getDurableObjectStorage("COUNTER", {
name: "user-123",
});
await worker.fetch("/counter/user-123");
const rows = await storage.exec(
"SELECT value FROM counters WHERE id = ?",
"user-123"
);
expect(rows).toEqual([{ value: 1 }]);
#14417 34e696d Thanks @matthewdavidrodgers! - Improve asset serving performance by removing an unnecessary internal dispatch hop
Asset requests and RPC calls now avoid an extra internal forwarding layer, reducing latency. The forwarding infrastructure is preserved for future use by cohort-based deployments.
#14682 d39ae01 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260710.1 | ^5.20260714.1 |
| workerd | 1.20260710.1 | 1.20260714.1 |
#14562 9f04a7e Thanks @martijnwalraven! - Keep reporting uncaught Worker errors when a stack frame's file URL has no local path
fileURLToPath throws on file:// URLs that cannot be represented as a local path (a non-local host; on Windows, any drive-less path — which is every file:///... URL reported by a POSIX-built bundle). Both the source-mapping machinery and youch's error-page frame parsing convert stack-frame specifiers this way, so one such frame previously failed the whole pretty-error request: the error page was replaced by a raw Node stack, the error was not logged, and handleUncaughtError did not fire. Source mapping now degrades to the unmapped stack and the pretty page falls back to a plain stack response instead.
#14418 cb30df3 Thanks @matthewdavidrodgers! - Improve routing performance for Workers with assets
Reduce request handling latency by streamlining the router Worker's request path. The loopback infrastructure remains available for future use.
#14727 3f3afbb Thanks @ascorbic! - Prevent local Browser Rendering teardown from hanging when Chrome does not exit
Miniflare now bounds graceful Chrome shutdown and forcefully terminates the browser process tree when needed, preventing disposal from waiting indefinitely.
#14723 e6fbc4e Thanks @ascorbic! - Prevent concurrent Miniflare instances from deleting each other's temporary email sessions
Email session cleanup now removes only the current instance's session directory and leaves the shared parent intact, avoiding startup failures when multiple local runtimes use the same project.
This lets users verify how a Durable Object recovers after its instance is torn down.
#14602 7692a61 Thanks @edmundhung! - Add unsafeEvictDurableObject() for targeted Durable Object eviction
This lets users verify how a Durable Object recovers after its instance is torn down.
#14602 7692a61 Thanks @edmundhung! - Allow listDurableObjectIds() to accept Durable Object class names as well as binding names.
#14627 ed33326 Thanks @tpmmorris! - Add convenient logging for worker emails in the project directory. In addition to the system's temp directory, logs for emails sent by workers are also written to a local temp directory defined by the calling process, e.g for an simple text email sent via Wrangler this is .wrangler/tmp/email/<session>/email-text/<message-uuid>.txt (and related files) in the project root. Callers of Miniflare can control this location via the new defaultProjectTmpPath option, which Wrangler and Vite plugin now set automatically.
#14642 018574b Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| @cloudflare/workers-types | ^5.20260708.1 | ^5.20260710.1 |
| workerd | 1.20260708.1 | 1.20260710.1 |
A step's retries.delay can now be a function that computes the delay per failed attempt, in addition to a static duration. The function receives { ctx
#14535 1b965c5 Thanks @Naapperas! - Support dynamic retry delays for Workflow steps in local dev
A step's retries.delay can now be a function that computes the delay per failed attempt, in addition to a static duration. The function receives { ctx, error } and returns a delay (a number of milliseconds or a duration string like "30 seconds"), and its result is fed into the configured backoff.
await step.do(
"call flaky API",
{
retries: {
limit: 5,
backoff: "constant",
delay: ({ ctx }) => ctx.attempt * 1000,
},
},
async () => {
/* ... */
}
);
The function is invoked once per failed attempt with a 5 second timeout. If it throws, times out, or returns an invalid value, the step fails without further retries.
Miniflare now exposes listDurableObjectIds() for listing persisted Durable Object instance IDs by binding name. The Vitest pool now uses this shared M
#14489 e3f0cd6 Thanks @edmundhung! - Add listDurableObjectIds() to Miniflare
Miniflare now exposes listDurableObjectIds() for listing persisted Durable Object instance IDs by binding name. The Vitest pool now uses this shared Miniflare API internally instead of duplicating Miniflare's storage listing logic.
#14465 2fedb1f Thanks @vaishnav-mk! - Add rollback support when terminating Workflow instances
WorkflowInstance.terminate({ rollback: true }) now runs registered rollback handlers before marking a local Workflow instance as terminated. Wrangler also supports this via wrangler workflows instances terminate --rollback, including local mode.
The rollback option is only sent for terminate operations and is rejected by the Local Explorer API for pause, resume, and restart actions.
#14596 8511ddf Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260706.1 | 1.20260708.1 |
| @cloudflare/workers-types | ^5.20260706.1 | ^5.20260708.1 |
The following dependency versions have been updated:
#14567 0852346 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler", "create-cloudflare"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260702.1 | 1.20260706.1 |
| @cloudflare/workers-types | 4.20260702.1 | 5.20260706.1 |
Queue producers can now send messages to consumers running in a separate local dev process. Messages produced before the consumer process has register
#14469 e7e5780 Thanks @connyay! - Support Queues across separate local dev processes
Queue producers can now send messages to consumers running in a separate local dev process. Messages produced before the consumer process has registered, or while it is down or reloading, are dropped rather than buffered, with a debug-level log emitted.
#14514 d88555e Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260701.1 | 1.20260702.1 |
#14492 1ac96a1 Thanks @penalosa! - Replace the CommonJS xdg-app-paths dependency with a vendored pure-ESM implementation
xdg-app-paths (and its xdg-portable/os-paths dependencies) are CommonJS only, which caused "Dynamic require of 'path' is not supported" errors when the surrounding code was bundled to ESM. The global config/cache directory resolution is now provided by a small, dependency-free pure-ESM module in @cloudflare/workers-utils that reproduces the previous path resolution exactly (verified against the real package in unit tests), so existing config and credential locations are unchanged. This also drops the transitive fsevents optional dependency that xdg-app-paths pulled in.
Miniflare and create-cloudflare now consume the shared helpers from @cloudflare/workers-utils instead of maintaining their own copies, importing node-only leaf entry points (@cloudflare/workers-utils/fs-helpers, @cloudflare/workers-utils/global-wrangler-config-path) where ESM bundling is required.
#14572 f416dd9 Thanks @petebacondarwin! - Key local rate limit counters by namespace_id instead of binding name
wrangler dev and Miniflare previously tracked each rate limit binding's counter by its binding name, so two bindings that referenced the same namespace_id were treated as separate limiters. Counters are now keyed by namespace_id, matching production: bindings that share a namespace_id share a limit, while distinct namespaces stay isolated. This also re-enables rate limit bindings in multiworker wrangler dev sessions, where they were previously stripped from secondary Workers to avoid a startup crash.
#14409 16fbf81 Thanks @matingathani! - reset() from cloudflare:test now resets ratelimit binding state between tests. Previously, RATE_LIMITERS bindings retained their in-memory bucket counts across test boundaries, causing later tests in the same file to see stale rate-limit exhaustion state.
The following dependency versions have been updated:
#14502 6b0ce98 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260630.1 | 1.20260701.1 |
The following dependency versions have been updated:
#14490 75d8cb0 Thanks @petebacondarwin! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260625.1 | 1.20260629.1 |
#14478 f10d4ad Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260629.1 | 1.20260630.1 |
#14490 75d8cb0 Thanks @petebacondarwin! - Fix edge cases on the local R2 public bucket endpoint (/cdn-cgi/local/r2/public) to match r2.dev: write methods are rejected with 401, malformed/multiple/inverted ranges with 400 and unsatisfiable ranges (including bytes=-0) with 416, Range is honored on HEAD requests with a bodyless 206, Content-Range is correct for suffix ranges, object keys are percent-decoded exactly once (keys containing a literal % no longer fail), and objects stored without a content type are served as application/octet-stream instead of omitting the Content-Type header. Unread object bodies are also cancelled (on HEAD and unsatisfiable-range responses) instead of leaking a read stream until garbage collection.
#14490 75d8cb0 Thanks @petebacondarwin! - Add Workflow introspection to createTestHarness()
Worker handles can now introspect Workflow bindings by name, allowing tests to disable sleeps, mock step results, and wait for Workflow outcomes. Tests can introspect a known Workflow instance by ID or track instances created after introspection starts.
const harness = createTestHarness({
workers: [{ configPath: "./wrangler.json" }],
});
const worker = harness.getWorker();
await using workflow = await worker.introspectWorkflow("MY_WORKFLOW");
await workflow.modifyAll((modifier) =>
modifier.disableSleeps([{ name: "wait-for-approval" }])
);
const response = await worker.fetch("/start-workflow");
const [instance] = await workflow.get();
await instance.waitForStatus("complete");
The following dependency versions have been updated:
#14406 3b743c1 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260623.1 | 1.20260625.1 |
The following dependency versions have been updated:
#14364 a085dec Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260617.1 | 1.20260619.1 |
#14383 9a0de8f Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260619.1 | 1.20260621.1 |
#14397 fab565f Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260621.1 | 1.20260623.1 |
A Uint8Array returned from a Workflows step under wrangler dev was serialised together with its full underlying ArrayBuffer, causing a raw SQLITE_TOOB
#14118 b38823f Thanks @aicayzer! - Fix Uint8Array step outputs in local Workflows being persisted with the full backing ArrayBuffer
A Uint8Array returned from a Workflows step under wrangler dev was serialised together with its full underlying ArrayBuffer, causing a raw SQLITE_TOOBIG error at view sizes well below the documented 1MiB step-output limit. For example, a 200KB view sliced from an 800KB buffer (a common pattern from crypto.getRandomValues or arr.slice(...) on a larger pool) would fail. The view's bytes are now copied to a tight buffer before persistence, bringing local behaviour in line with production. Fixes #14101.
GHSA-96hv-2xvq-fx4p / CVE-2026-48779 (high severity) reports a remote memory-exhaustion DoS in ws@<8.21.0: a peer sending a high volume of tiny fragme…
#14347 673b09e Thanks @jamesopstad! - Update undici from 7.24.8 to 7.28.0
#14346 e930bd4 Thanks @haidargit! - Bump ws from 8.20.1 to 8.21.0 to address GHSA-96hv-2xvq-fx4p
GHSA-96hv-2xvq-fx4p / CVE-2026-48779 (high severity) reports a remote memory-exhaustion DoS in ws@<8.21.0: a peer sending a high volume of tiny fragments and data chunks over modest network traffic can crash a ws server or client via OOM. The fix shipped in ws@8.21.0 (commit 2b2abd45, released 2026-05-22), which also introduces the maxBufferedChunks and maxFragments options. This change bumps the workspace catalog entry so that miniflare, wrangler, and @cloudflare/vite-plugin all pick up the patched release.
#14314 5c3bb11 Thanks @harryzcy! - Bump esbuild to 0.28.1
This update includes several bug fixes from esbuild versions 0.27.3 through 0.28.1. See the esbuild changelog for details.
#14331 296ad65 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260616.1 | 1.20260617.1 |
fetch(url, { cf: { image: { ... } } }) now transforms images locally via Sharp, instead of returning the original bytes unchanged. This mirrors the pr
#14221 0e055d3 Thanks @mglewis! - Support cf.image (transform via Workers) image transformations in local dev
fetch(url, { cf: { image: { ... } } }) now transforms images locally via Sharp, instead of returning the original bytes unchanged. This mirrors the production "transform via Workers" feature, so Workers already using cf.image behave much more closely to production in wrangler dev.
As with the Images binding, cf.image transforms require Sharp to be installed — transforms are silently skipped if Sharp is unavailable.
#14271 27db82c Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260611.1 | 1.20260612.1 |
#14298 2a6a26b Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260612.1 | 1.20260615.1 |
#14317 9a424ed Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260615.1 | 1.20260616.1 |
#14287 41f391f Thanks @edmundhung! - Improve errors for missing resource bindings
When methods like getKVNamespace() or getR2Bucket() are called with a binding name that is not configured for that resource type, Miniflare now reports the expected binding type in the error message.
Each local R2 bucket is now exposed under /cdn-cgi/local/r2/public/ / on the existing user-facing dev server. The is the bucket's id when set, otherwi
#14119 2047a32 Thanks @tahmid-23! - Add support for serving R2 bucket objects publicly via the dev server
Each local R2 bucket is now exposed under /cdn-cgi/local/r2/public/<bucket-id>/<key> on the existing user-facing dev server. The <bucket-id> is the bucket's id when set, otherwise its binding name. Buckets with a remoteProxyConnectionString are not exposed. The endpoint supports GET and HEAD, range requests, conditional headers, and forwards stored HTTP metadata.
#14246 f3990b2 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260609.1 | 1.20260610.1 |
#14256 4597f08 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260610.1 | 1.20260611.1 |
The following dependency versions have been updated:
#14192 d076bcc Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260603.1 | 1.20260605.1 |
#14217 24497d0 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260605.1 | 1.20260608.1 |
#14231 4bb572f Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260608.1 | 1.20260609.1 |
#14177 48c4ff0 Thanks @ktKongTong! - Enable local scheduled handler dispatch for Workers + Assets (#9882)
It is now possible to trigger a scheduled handler on a Worker that has assets.
Pre-launch rename of the public binding type from web_search to websearch so the on-the-wire shape matches the product name (Web Search). The wrangler
#14164 b502d54 Thanks @G4brym! - Rename the web_search binding kind to websearch
Pre-launch rename of the public binding type from web_search to websearch so the on-the-wire shape matches the product name (Web Search). The wrangler config key, the binding-type string sent to the Cloudflare API, and the miniflare option key all move from web_search / webSearch to websearch.
Update your wrangler config:
- "web_search": { "binding": "WEBSEARCH" }
+ "websearch": { "binding": "WEBSEARCH" }
The runtime WebSearch type exposed on env.WEBSEARCH is unchanged.
#13863 3b8b80a Thanks @aslakhellesoy! - Support cross-worker workflow bindings via the dev registry
When a workflow binding has a scriptName that refers to a worker registered in another Miniflare instance (via unsafeDevRegistryPath), miniflare now reroutes the engine's USER_WORKFLOW binding through the dev-registry-proxy worker — the same mechanism Durable Objects already use for cross-worker scriptName bindings.
Previously the workflow engine was bound directly to a local service core:user:<scriptName>, so workerd refused to start when that script lived in a different process.
This unblocks getPlatformProxy() (and any other split-Miniflare setup) for users whose workflow class is defined in a separate worker — for example SvelteKit/Remix on Cloudflare, where adapter-cloudflare's dev integration runs the user's worker in a sidecar.
See #7459.
#14175 a3eea27 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260601.1 | 1.20260603.1 |
#14081 1fdd8de Thanks @dario-piotrowicz! - Detect early workerd exit instead of hanging indefinitely
When workerd exits during startup before writing all expected listen events to the control file descriptor (e.g. due to an IPv6 bind failure, permission error, or missing library), Miniflare's waitForPorts() would block forever. This caused wrangler dev to stall at "Starting local server..." with no error and no timeout.
The fix races waitForPorts() against the child process exit event so that any unexpected workerd termination is detected immediately. When workerd exits early, Miniflare now throws ERR_RUNTIME_FAILURE with the runtime's stderr output included in the error message, making the root cause diagnosable without external tools.
The following dependency versions have been updated:
#14147 e06cbb7 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260529.1 | 1.20260601.1 |
#14086 4ef790b Thanks @dario-piotrowicz! - Use 127.0.0.1 instead of localhost for the runtime inspector address
On systems where getaddrinfo("localhost") returns ::1 but IPv6 is disabled at the kernel level, workerd fails to bind the inspector socket and silently continues without emitting the listen-inspector event to the control FD. This caused wrangler dev to hang indefinitely at "Starting local server..." with no error output.
Using 127.0.0.1 explicitly is consistent with DEFAULT_HOST, --debug-port, and resolveLocalhost() already in the codebase.
#14105 337e912 Thanks @dario-piotrowicz! - Remove trailing periods from URLs in terminal output
URLs printed to the terminal with a sentence-ending period (e.g. https://example.com/path.) would include the period when clicked in some terminal emulators, causing 404 errors. This removes trailing periods from all URLs displayed in CLI output across wrangler, miniflare, vitest-pool-workers, and workers-utils.
#14112 3a746ac Thanks @penalosa! - Pin non-bundled runtime dependencies to exact versions
Dependencies that are not bundled into a package's published output are installed directly into consumers' dependency trees, so they are now pinned to exact versions instead of semver ranges. This closes a supply-chain gap where an unpinned external dependency could resolve to a compromised upstream release on a fresh install. A new pnpm check:pinned-deps lint enforces this for all published packages (and for the shared pnpm catalog) going forward.
The old pipeline field is still accepted but deprecated and will emit a warning.
#14087 e3c862a Thanks @edmundhung! - Add support for the new web_search binding kind.
Cloudflare Web Search is a managed, zero-setup web discovery primitive for agents and Workers. Declare the binding as a single object in wrangler.jsonc:
{
"web_search": { "binding": "WEBSEARCH" }
}
There is exactly one shared web corpus, so there is no namespace, instance, or other field to specify -- only the variable name. The binding exposes a single search() method that returns URLs and catalog metadata for a query. Web Search is discovery-only -- to read a result's content the caller invokes the global fetch() API against the result's url.
The binding is always remote in local development: Miniflare proxies to the production Web Search service via the remote-bindings transport. Adds the websearch.run OAuth scope to wrangler login.
Also adds a wrangler websearch search command for running ad-hoc queries from the CLI:
npx wrangler websearch search "cloudflare workers"
npx wrangler websearch search "cloudflare workers" --limit 5
npx wrangler websearch search "cloudflare workers" --json
--limit is optional (defaults to 10, capped at 20). --json prints the raw response; without it the results render as a pretty table.
#13610 cbb39bd Thanks @petebacondarwin! - Add support for agent_memory bindings
Agent Memory bindings allow Workers to connect to Cloudflare's Agent Memory service for storing and retrieving agent conversation state. This binding is remote-only, meaning it always connects to the Cloudflare API during wrangler dev rather than using a local simulation.
To configure an agent_memory binding, add the following to your wrangler.json:
{
"agent_memory": [
{
"binding": "MY_MEMORY",
"namespace": "my-namespace"
}
]
}
Wrangler will automatically provision the namespace during deployment if it does not already exist. Type generation via wrangler types is also supported.
This change also adds the agent-memory:write OAuth scope to Wrangler's default login scopes, so wrangler login can request the permissions needed to provision and manage Agent Memory namespaces.
#14087 e3c862a Thanks @edmundhung! - Rename pipeline field to stream in pipeline bindings configuration
The pipeline field inside pipelines bindings has been renamed to stream to align with the updated API wire format. The old pipeline field is still accepted but deprecated and will emit a warning.
Before:
// wrangler.json
{
"pipelines": [
{
"binding": "MY_PIPELINE",
"pipeline": "my-stream-name"
}
]
}
After:
// wrangler.json
{
"pipelines": [
{
"binding": "MY_PIPELINE",
"stream": "my-stream-name"
}
]
}
#14079 972d13d Thanks @edmundhung! - Add JSON output to /cdn-cgi/handler/scheduled
The /cdn-cgi/handler/scheduled endpoint now accepts ?format=json to return the scheduled handler result as JSON, including whether the handler called controller.noRetry(). Requests without format=json still return the existing text outcome for backward compatibility.
#14106 7bb5c7a Thanks @dario-piotrowicz! - Add timeout to browser-rendering browser launch to prevent infinite hangs
The browser-rendering plugin's launchBrowser() function now passes a 5-minute timeout to waitForLineOutput() when waiting for Chrome to print its DevTools WebSocket URL. Previously, if Chrome failed to start or crashed before printing the URL, the promise would hang forever. This could cause CI pipelines and local dev sessions to get stuck indefinitely.
#14087 e3c862a Thanks @edmundhung! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260526.1 | 1.20260527.1 |
#14076 97d7d81 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260527.1 | 1.20260528.1 |
#14100 c647ccc Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260528.1 | 1.20260529.1 |
#14087 e3c862a Thanks @edmundhung! - Fix wrangler dev crash under Yarn PnP when the worker emits a structured log or the inspector forwards a stack trace.
getFreshSourceMapSupport was unconditionally indexing require.cache, but when miniflare is imported from ESM under Yarn PnP, Node's ESM->CJS bridge (loadCJSModule in node:internal/modules/esm/translators) hands the wrapped CJS module a re-invented require that only carries .resolve and .main, with no .cache. Fall back to createRequire(__filename) in that case so the fresh-load cache-swap keeps working.
The following dependency versions have been updated:
#14003 c1fd2fd Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260521.1 | 1.20260526.1 |
#14011 420e457 Thanks @petebacondarwin! - Warn when a remote-bindings request is blocked by Cloudflare Access
When wrangler dev is used with remote bindings and a request from the local remote-bindings proxy client to the remote workers.dev proxy server is blocked by Cloudflare Access (HTTP 403 with the Cloudflare Access block page), Wrangler now:
CLOUDFLARE_ACCESS_CLIENT_ID / CLOUDFLARE_ACCESS_CLIENT_SECRET (Service Token credentials) or run cloudflared access login to authenticate.InferenceUpstreamError from env.AI.run()) and any browser response piped back via a service binding .fetch().Previously the 403 was returned to user code with the full Access HTML, which both drowned out other logs and made it hard to tell that the failure was due to Cloudflare Access on workers.dev rather than a problem in the binding itself or the deployed proxy server. The detection runs inside the proxy client worker (which only ever talks to the remote-bindings proxy URL), so it does not trigger false positives on user-worker 403s.
The following dependency versions have been updated:
#13993 0733688 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260520.1 | 1.20260521.1 |
#13999 30657e1 Thanks @edmundhung! - Fix TCP requests failing when outboundService is configured
Workers using outboundService can now open TCP connections with cloudflare:sockets. Previously, TCP requests could throw an error when a custom outbound service was configured.
GHSA-58qx-3vcg-4xpx / CVE-2026-45736 reports an uninitialized-memory disclosure in ws@<8.20.1 when a TypedArray is passed as the reason argument to We…
#13978 fa1f61f Thanks @sassyconsultingllc! - Bump ws from 8.18.0 to 8.20.1 to address GHSA-58qx-3vcg-4xpx
GHSA-58qx-3vcg-4xpx / CVE-2026-45736 reports an uninitialized-memory disclosure in ws@<8.20.1 when a TypedArray is passed as the reason argument to WebSocket.close(). The fix shipped in ws@8.20.1 on 2026-05-12. This change bumps the workspace catalog entry so that miniflare, wrangler, and @cloudflare/vite-plugin all pick up the patched release.
#13977 2679e05 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260518.1 | 1.20260519.1 |
#13984 7e40d98 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260519.1 | 1.20260520.1 |
#13912 d803737 Thanks @petebacondarwin! - Fix /cdn-cgi/* host validation incorrectly accepting subdomains of exact configured routes
Miniflare's /cdn-cgi/* host/origin validator was treating exact configured routes the same as wildcard configured routes, so a request whose Host or Origin hostname was a subdomain of an exact route (e.g. sub.my-custom-site.com for a my-custom-site.com/* route) was incorrectly accepted. Exact configured routes and the configured upstream hostname are now required to match the request hostname exactly. Subdomain matching is only applied to wildcard routes such as *.example.com/*. Localhost hostnames continue to be allowed as before.
This affects wrangler dev and local development through @cloudflare/vite-plugin, both of which use Miniflare under the hood.
#13971 59cd880 Thanks @petebacondarwin! - Improve error diagnostics in the Browser Run binding worker
When the local Browser Run binding failed to reach an upstream — for example when Chrome failed to launch and miniflare's loopback /browser/launch endpoint returned a 500 with a stack-trace text body — the binding worker would call response.json() on the non-JSON body and throw an opaque SyntaxError: Unexpected token X, "..." is not valid JSON. The actual upstream error message (e.g. Chrome readiness probe at ... timed out after 5000ms) was discarded.
The binding worker now reads the response body as text first, surfaces the HTTP status and body content in the thrown error, and chains the original SyntaxError via cause when the body was a 2xx response that didn't parse as JSON. This makes both local-dev failures and CI test flakes self-diagnosing.
#13980 e8c2031 Thanks @petebacondarwin! - Recover from corrupted @puppeteer/browsers cache when launching a Browser Run session
When Miniflare's local Browser Run binding launches Chrome, it calls @puppeteer/browsers' install() to ensure the binary is present. If a previous install() was interrupted mid-extraction (test timeout, process kill, antivirus quarantine), the cache directory can be left partially populated — the folder exists but the executable inside it is missing. install() then throws The browser folder (...) exists but the executable (...) is missing on every subsequent call within the same process and the entire test session, breaking every later Browser Run operation until the cache is manually cleared.
launchBrowser now catches that specific error, removes the corrupted cache directory, and retries install() once. If the corruption persists after cleanup, the original error is rethrown with a clearer message.
This complements #13971, which surfaced the original error from inside the binding worker. With that diagnostic in place and this self-healing layer, the previously-intermittent "browser folder exists but executable missing" failure mode should no longer fail an entire CI run.
The following dependency versions have been updated:
b27eb18 Thanks @benjamincburns! - Bumped miniflare deps acorn to 8.16.0 and acorn-walk to 8.3.5 to add support for the using and await using keywords when miniflare parses scripts.#13948 b25dc0d Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260515.1 | 1.20260518.1 |
#13932 ebf4b24 Thanks @zebp! - Fix local Workflow startup when compatibility flags include experimental
Miniflare now deduplicates compatibility flags for the internal Workflow engine service. This prevents wrangler dev from failing with Compatibility flag specified multiple times: experimental when the user's Worker already enables that flag.
The following dependency versions have been updated:
#13926 19ed49a Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260511.1 | 1.20260515.1 |
The following dependency versions have been updated:
#13894 58b4403 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260508.1 | 1.20260511.1 |
#13646 f781a2b Thanks @emily-shen! - Propagate cf-trace-id header on remote binding proxy requests
When the CF_TRACE_ID environment variable is set, its value is now forwarded as a cf-trace-id header on outgoing remote binding proxy requests. This makes it easier to correlate traces when debugging remote bindings in local development.
The following dependency versions have been updated:
5d936c5 Thanks @penalosa! - Support workerd autogates via the MINIFLARE_WORKERD_AUTOGATES environment variable.#13866 4e44ce6 Thanks @dependabot! - Update dependencies of "miniflare", "wrangler"
The following dependency versions have been updated:
| Dependency | From | To |
|---|---|---|
| workerd | 1.20260507.1 | 1.20260508.1 |
Your coding agent can read these notes before it upgrades. Set up the MCP server →
{ "k2": [ { "binding": "ORDERS", "stream": "0123456789abcdef0123456789abcdef" } ] }