Skip to content

These docs are for Miniflare 2 which is no longer supported apart from critical security updates.
Please see the migration guide to upgrade to Miniflare 3, and the updated API docs.

Visit Miniflare on GitHub
Set theme to dark (⇧+D)

⬆️ Migrating from Version 2

Miniflare v3 now uses workerd, the open-source Cloudflare Workers runtime. This is the same runtime that's deployed on Cloudflare’s network, giving bug-for-bug compatibility and practically eliminating behavior mismatches. Refer to the Miniflare v3 and Wrangler v3 announcements for more information.

Missing Features

Several features from Miniflare v2 are not supported in Miniflare v3's initial release. However, they are on the roadmap, and will be added soon:

  • Step-through debugging
  • Automatically triggering scheduled events via CRON schedules, or manually triggering them via /.mf/scheduled or /cdn-cgi/mf/scheduled (manually triggering events is supported via the --test-scheduled Wrangler flag and visiting /__scheduled)
  • Starting an HTTPS server

CLI Changes

Miniflare v3 no longer includes a standalone CLI. To get the same functionality, you will need to switch over to Wrangler. Wrangler v3 uses Miniflare v3 by default. To start a local development server, run:

$ npx wrangler@3 dev

If there are features from the Miniflare CLI you would like to see in Wrangler, please open an issue on GitHub.

API Changes

We have tried to keep Miniflare v3’s API close to Miniflare v2 where possible, but many options and methods have been removed or changed with the switch to the open-source workerd runtime. See the GitHub README for the new API docs.

Updated Options

  • kvNamespaces/r2Buckets/d1Databases

    • In addition to string[]s, these options now accept Record<string, string>s, mapping binding names to namespace IDs/bucket names/database IDs. This means multiple Workers can bind to the same namespace/bucket/database under different names.
  • queueBindings

    • Renamed to queueProducers. This either accepts a Record<string, string> mapping binding names to queue names, or a string[] of binding names to queues of the same name.
  • queueConsumers

    • Either accepts a Record<string, QueueConsumerOptions> mapping queue names to consumer options, or a string[] of queue names to consume with default options. QueueConsumerOptions has the following type:

      interface QueueConsumerOptions {
      maxBatchSize?: number; // default: 5
      maxBatchTimeout?: number /* seconds */; // default: 1
      maxRetries?: number; // default: 2
      deadLetterQueue?: string; // default: none
  • cfFetch

    • Renamed to cf. Either accepts a boolean, string (as before), or an object to use a the cf object for incoming requests.

Removed Options

  • wranglerConfigPath/wranglerConfigEnv

  • packagePath

    • Miniflare no longer loads script paths from package.json files. Use the scriptPath option to specify your script instead.
  • watch

  • logUnhandledRejections

  • globals

  • https/httpsKey(Path)/httpsCert(Path)/httpsPfx(Path)/httpsPassphrase

    • Miniflare does not support starting HTTPS servers yet. These options may be added back in a future release.
  • crons

  • mounts

    • Miniflare no longer has the concept of parent and child Workers. Instead, all Workers can be defined at the same level, using the new workers option. Here's an example that uses a service binding to increment a value in a shared KV namespace:

      import { Miniflare, Response } from "miniflare";
      const message = "The count is ";
      const mf = new Miniflare({
      // Options shared between workers such as HTTP and persistence configuration
      // should always be defined at the top level.
      host: "",
      port: 8787,
      kvPersist: true,
      workers: [
      name: "worker",
      kvNamespaces: { COUNTS: "counts" },
      serviceBindings: {
      INCREMENTER: "incrementer",
      // Service bindings can also be defined as custom functions, with access
      // to anything defined outside Miniflare.
      async CUSTOM(request) {
      // `request` is the incoming `Request` object.
      return new Response(message);
      modules: true,
      script: `export default {
      async fetch(request, env, ctx) {
      // Get the message defined outside
      const response = await env.CUSTOM.fetch("http://host/");
      const message = await response.text();
      // Increment the count 3 times
      await env.INCREMENTER.fetch("http://host/");
      await env.INCREMENTER.fetch("http://host/");
      await env.INCREMENTER.fetch("http://host/");
      const count = await env.COUNTS.get("count");
      return new Response(message + count);
      name: "incrementer",
      // Note we're using the same `COUNTS` namespace as before, but binding it
      // to `NUMBERS` instead.
      kvNamespaces: { NUMBERS: "counts" },
      // Worker formats can be mixed-and-matched
      script: `addEventListener("fetch", (event) => {
      async function handleRequest() {
      const count = parseInt((await NUMBERS.get("count")) ?? "0") + 1;
      await NUMBERS.put("count", count.toString());
      return new Response(count.toString());
      const res = await mf.dispatchFetch("http://localhost");
      console.log(await res.text()); // "The count is 3"
      await mf.dispose();
  • metaProvider

    • The cf object and X-Forwarded-Proto/X-Real-IP headers can be specified when calling dispatchFetch() instead. A default cf object can be specified using the new cf option too.
  • durableObjectAlarms

    • Miniflare now always enables Durable Object alarms.
  • globalAsyncIO/globalTimers/globalRandom

  • actualTime

    • Miniflare now always returns the current time.
  • inaccurateCpu

    • Set the inspectorPort: 9229 option to enable the V8 inspector. Visit chrome://inspect in Google Chrome to open DevTools and perform CPU profiling.

Updated Methods

  • setOptions()
    • Miniflare v3 now requires a full configuration object to be passed, instead of a partial patch.

Removed Methods

  • reload()
    • Call setOptions() with the original configuration object to reload Miniflare.
  • createServer()/startServer()
  • dispatchScheduled()/startScheduled()
  • dispatchQueue()
  • getGlobalScope()/getBindings()/getModuleExports()
  • getKVNamespace()/getR2Bucket()/getCaches()/getDurableObjectNamespace()
    • Similarly, these methods return instances of Workers runtime classes that are defined in a different process, and can no longer be supported.
  • addEventListener()/removeEventListener()
    • Miniflare no longer emits reload events. As Miniflare no longer watches files, reloads are only triggered by initialisation or setOptions() calls. In these cases, it's possible to wait for the reload with either await mf.ready or await mf.setOptions() respectively.
  • Response#waitUntil()

Removed Packages

  • @miniflare/*
    • Miniflare is now contained within a single miniflare package.