What is miniflare?
Miniflare is a simulator for Cloudflare Workers, allowing you to develop and test your Workers locally. It provides a local environment that mimics the Cloudflare Workers runtime, enabling you to test your code without deploying it to the cloud.
What are miniflare's main functionalities?
Local Development
Miniflare allows you to run and test your Cloudflare Workers locally. This example demonstrates how to create a simple worker that responds with 'Hello from Miniflare!' to any request.
const { Miniflare } = require('miniflare');
const mf = new Miniflare({
script: `addEventListener('fetch', event => {
event.respondWith(new Response('Hello from Miniflare!'));
})`
});
(async () => {
const res = await mf.dispatchFetch('http://localhost');
console.log(await res.text()); // Hello from Miniflare!
})();
KV Storage Simulation
Miniflare can simulate Cloudflare Workers KV storage, allowing you to test interactions with KV namespaces locally. This example shows how to store and retrieve a value from a KV namespace.
const { Miniflare } = require('miniflare');
const mf = new Miniflare({
script: `addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const value = await MY_KV_NAMESPACE.get('key');
return new Response(value);
}`,
kvNamespaces: ['MY_KV_NAMESPACE']
});
(async () => {
await mf.getKVNamespace('MY_KV_NAMESPACE').put('key', 'value');
const res = await mf.dispatchFetch('http://localhost');
console.log(await res.text()); // value
})();
Durable Objects Simulation
Miniflare supports simulating Durable Objects, which are used for stateful logic in Cloudflare Workers. This example demonstrates a simple counter Durable Object that increments its value with each request.
const { Miniflare } = require('miniflare');
const mf = new Miniflare({
script: `class Counter {
constructor(state, env) {
this.state = state;
this.env = env;
}
async fetch(request) {
let value = (await this.state.storage.get('value')) || 0;
value++;
await this.state.storage.put('value', value);
return new Response(value);
}
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const id = 'counter';
const stub = await COUNTER.get(id);
return stub.fetch(request);
}`,
durableObjects: { COUNTER: 'Counter' }
});
(async () => {
const res1 = await mf.dispatchFetch('http://localhost');
console.log(await res1.text()); // 1
const res2 = await mf.dispatchFetch('http://localhost');
console.log(await res2.text()); // 2
})();
Other packages similar to miniflare
wrangler
Wrangler is the official CLI tool for managing Cloudflare Workers. It allows you to develop, test, and deploy Workers, but unlike Miniflare, it does not provide a local simulation environment. Instead, it focuses on deployment and management tasks.
worktop
Worktop is a lightweight framework for building Cloudflare Workers. It provides utilities for routing, handling requests, and managing responses. While it simplifies the development of Workers, it does not offer the local simulation capabilities that Miniflare provides.
๐ฅ Miniflare
Miniflare is a simulator for developing and testing
Cloudflare Workers.
- ๐ Fun: develop workers easily with detailed logging, file watching and
pretty error pages supporting source maps.
- ๐ Full-featured: supports most Workers features, including KV, Durable
Objects, WebSockets, modules and more.
- โก Fully-local: test and develop Workers without an internet connection.
Reload code on change quickly.
It's an alternative to wrangler dev
, written in TypeScript, that runs your
workers in a sandbox implementing Workers' runtime APIs.
See https://v2.miniflare.dev for more detailed documentation.
โ ๏ธ This branch is for the next major version of Miniflare, which is under
development.
Miniflare 2 has been completely redesigned from version 1 with 3 primary design
goals:
- ๐ Modular: Miniflare 2 splits Workers components (KV, Durable Objects,
etc.) into separate packages (
@miniflare/kv
,
@miniflare/durable-objects
, etc.) that you can import separately for
testing. - โจ Lightweight: Miniflare 1 included
122 third-party packages with a
total install size of
88.3MB
. Miniflare 2 reduces this to 23 packages and
6.2MB
๐คฏ. - โ
Correct: Miniflare 2 more accurately replicates the quirks and thrown
errors of the real Workers runtime, so you'll know before you deploy if
things are going to break.
Features
- ๐จ Fetch Events (with HTTP(S) server and manual dispatch)
- โฐ Scheduled Events (with cron triggering and manual dispatch)
- ๐ Variables and Secrets with
.env
Files - ๐ Modules Support
- ๐ฆ KV (with optional persistence)
- โจ Cache (with optional persistence)
- ๐ Durable Objects (with optional persistence)
- ๐ Workers Sites
- โ๏ธ WebSockets
- ๐ Custom & Wrangler Builds Support
- โ๏ธ WebAssembly Support
- ๐บ Source Map Support
- ๐ธ Web Standards: Base64, Timers, Fetch, Encoding, URL, Streams, Crypto
- ๐ HTMLRewriter
- โก๏ธ Live Reload on File Changes
- ๐
Compatibility Dates/Flags Support
- ๐ Multiple Workers Support
- ๐คน Custom Jest Environment (with isolated per-test storage)
- ๐ช Written in TypeScript
Install
Miniflare is installed using npm:
$ npm install -g miniflare@next
$ npm install -D miniflare@next
Using the CLI
$ miniflare worker.js --watch --debug
[mf:dbg] Options:
[mf:dbg] - Scripts: worker.js
[mf:dbg] Reloading worker.js...
[mf:inf] Worker reloaded! (97B)
[mf:dbg] Watching .env, package.json, worker.js, wrangler.toml...
[mf:inf] Listening on :8787
[mf:inf] - http://127.0.0.1:8787
Using the API
import { Miniflare } from "miniflare";
const mf = new Miniflare({
script: `
addEventListener("fetch", (event) => {
event.respondWith(new Response("Hello Miniflare!"));
});
`,
});
const res = await mf.dispatchFetch("http://localhost:8787/");
console.log(await res.text());
CLI Reference
Usage: miniflare [script] [options]
Core Options:
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
-c, --wrangler-config Path to wrangler.toml [string]
--wrangler-env Environment in wrangler.toml to use [string]
--package Path to package.json [string]
-m, --modules Enable modules [boolean]
--modules-rule Modules import rule [array:TYPE=GLOB]
--compat-date Opt into backwards-incompatible changes from [string]
--compat-flag Control specific backwards-incompatible changes [array]
-u, --upstream URL of upstream origin [string]
-w, --watch Watch files for changes [boolean]
-d, --debug Enable debug logging [boolean]
-V, --verbose Enable verbose logging [boolean]
--(no-)update-check Enable update checker (enabled by default) [boolean]
--root Path to resolve files relative to [string]
--mount Mount additional named workers [array:NAME=PATH[@ENV]]
HTTP Options:
-H, --host Host for HTTP(S) server to listen on [string]
-p, --port Port for HTTP(S) server to listen on [number]
--https Enable self-signed HTTPS (with optional cert path) [boolean/string]
--https-key Path to PEM SSL key [string]
--https-cert Path to PEM SSL cert chain [string]
--https-ca Path to SSL trusted CA certs [string]
--https-pfx Path to PFX/PKCS12 SSL key/cert chain [string]
--https-passphrase Passphrase to decrypt SSL files [string]
--(no-)cf-fetch Path for cached Request cf object from Cloudflare [boolean/string]
--live-reload Reload HTML pages whenever worker is reloaded [boolean]
Scheduler Options:
-t, --cron CRON expression for triggering scheduled events [array]
Build Options:
-B, --build-command Command to build project [string]
--build-base-path Working directory for build command [string]
--build-watch-path Directory to watch for rebuilding on changes [array]
KV Options:
-k, --kv KV namespace to bind [array]
--kv-persist Persist KV data (to optional path) [boolean/string]
Durable Objects Options:
-o, --do Durable Object to bind [array:NAME=CLASS[@MOUNT]]
--do-persist Persist Durable Object data (to optional path) [boolean/string]
Cache Options:
--(no-)cache Enable default/named caches (enabled by default) [boolean]
--cache-persist Persist cached data (to optional path) [boolean/string]
Sites Options:
-s, --site Path to serve Workers Site files from [string]
--site-include Glob pattern of site files to serve [array]
--site-exclude Glob pattern of site files not to serve [array]
Bindings Options:
-e, --env Path to .env file [string]
-b, --binding Binds variable/secret to environment [array:KEY=VALUE]
--global Binds variable/secret to global scope [array:KEY=VALUE]
--wasm WASM module to bind [array:NAME=PATH]
Acknowledgements
Many thanks to
dollarshaveclub/cloudworker
and
gja/cloudflare-worker-local
for inspiration.
Durable Object's transactions are implemented using Optimistic Concurrency
Control (OCC) as described in
"On optimistic methods for concurrency control." ACM Transactions on Database Systems.
Thanks to Alistair O'Brien for helping the
Miniflare author understand this.