github cloudflare/workers-sdk miniflare@5.20260825.0-alpha

Minor Changes

  • #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.

Patch Changes

  • #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.

Don't miss a new workers-sdk release

NewReleases is sending notifications on new releases.