Wrangler v3 makes local development the default
Cloudflare has released Wrangler v3, the first version of its Workers CLI where wrangler dev runs code locally by default using Miniflare v3, which is now built on the open-source workerd runtime — the same runtime that powers Cloudflare Workers in production.
This shift gives developers a local testing environment that closely matches production behavior: the same runtime and bindings, plus simulators for KV, R2, D1, Cache, and Queues. Unlike remote development, local mode doesn't bill operations against KV namespaces or R2 buckets, and paid features such as Durable Objects can be tested for free.
The local-first approach also brings measurable performance gains. Compared to the previous remote default, Wrangler v3 shows a 10x reduction in startup times and a 60x reduction in script reload times.
Keeping remote development available
Cloudflare isn't dropping remote mode. Developers who need to test against real data, or who want to exercise services like image resizing that aren't yet implemented locally, can run wrangler dev --remote to use Cloudflare's network as before.
What changes for Miniflare users
Miniflare v2 is being deprecated. Two things matter for existing users:
- CLI users must move to
wrangler dev— Miniflare v3 no longer ships its own CLI. - API users should upgrade to
miniflare@3and follow the official migration guide.
How Miniflare v3 works
Miniflare v3 delegates the runtime and bindings to workerd. Because workerd is server-first, each configuration opens at least one socket, and each socket is mapped to a service — which can be an external server, a disk directory, or a Worker. A minimal setup involves creating a worker.capnp config file, running npx workerd serve worker.capnp, and visiting http://localhost:8080.
using Workerd = import "/workerd/workerd.capnp";
const helloConfig :Workerd.Config = (
services = [
( name = "hello-worker", worker = .helloWorker )
],
sockets = [
( name = "hello-socket", address = "*:8080", http = (), service = "hello-worker" )
]
);
const helloWorker :Workerd.Worker = (
modules = [
( name = "worker.mjs",
esModule =
`export default {
` async fetch(request, env, ctx) {
` return new Response("Hello from workerd! 👋");
` }
`}
)
],
compatibilityDate = "2023-04-04",
);
What workerd doesn't provide are the underlying implementations for the rest of Cloudflare's Developer Platform products. That's where Miniflare fills in with its simulators for KV, R2, D1, Queues, and the Cache API.

A storage layer built on SQLite
Most of Miniflare's work is now about presenting storage interfaces. Miniflare v2 used a custom key-value store, which created several limitations. Miniflare v3 switches to SQLite for metadata, with a separate blob store for KV values, R2 objects, and cached responses.
SQLite provides more flexible querying, which opens the door to supporting future storage solutions. The separate blob store, meanwhile, enables efficient, ranged, streamed access to data. Blob identifiers are unguessable and blobs are immutable (though deletable), which makes atomic updates with the SQLite database possible — no other operation can interact with a blob until it's committed, since blobs can't be listed and their IDs can't be guessed.
Reimagining in-Worker unit tests
Miniflave v2 offered custom environments for Node.js testing frameworks like Jest and Vitest, letting developers run tests inside the Miniflare sandbox. That meant any function using Workers runtime APIs could be imported and called directly, not just exercised through HTTP requests. These environments also provided per-test isolated storage that automatically rolled back changes.
That approach was simple in v2 because the runtime APIs were reimplemented in Node.js and could be injected into the test framework's global scope. In v3, the runtime APIs live in a separate workerd process, and JavaScript classes can't be shared across process boundaries.
The proposed solution reuses Node's worker_threads concept — but instead of spawning a new OS thread, Miniflare spawns a new workerd process and communicates via WebSockets between the Node.js host and the workerd "thread."

A proof of concept with Vitest shows the approach works, with existing IDE integrations and the Vitest UI functioning without extra effort. It's not ready for release yet, but work will continue over the coming months. One requirement is that the workerd "thread" must access Node.js built-in modules, and Cloudflare has already begun rolling out support for that.
Bringing workerd to Windows
Before it was open-sourced, the Workers runtime was only designed for Linux. For Miniflare v3, Cloudflare needed macOS and Windows support too. macOS was a relatively straightforward port since it's Unix-based; Windows was harder.
workerd uses KJ, an alternative C++ base library that was already cross-platform. The runtime also migrated to the Bazel build system, which has solid Windows support. For compiling on Windows, Cloudflare uses LLVM's MSVC-compatible clang-cl driver rather than Microsoft's Visual C++ compiler. This made it possible to use the "same" compiler frontend across Linux, macOS, and Windows, cutting the porting effort significantly. It also brought proper handling of #pragma once with Bazel's symlinked virtual includes, support for __atomic_* functions, a standards-compliant preprocessor, GNU statement expressions used by some KJ macros, and default recognition of the .c++ extension.
After replacing Unix API calls with Windows equivalents under #if _WIN32 preprocessor directives, and fixing segmentation faults caused by differing execution order, workerd now runs natively on Windows — no WSL or Docker needed.
Getting started with Wrangler v3
Wrangler v3 is generally available. Upgrade with npm install --save-dev wrangler@3, then run npx wrangler dev to try the new local development experience. Feedback can be shared in the #wrangler channel on the Cloudflare Developers Discord, and bugs can be reported via GitHub issues.



