Skip to content
Miniflare
Visit Miniflare on GitHub
Set theme to dark (โ‡ง+D)

๐Ÿ•ธ Web Standards

Miniflare supports the following Web Standards in its sandbox:

  • Console: console.*
  • Timers: setTimeout, setInterval, clearTimeout, clearInterval, queueMicrotask, AbortSignal.timeout, scheduler.wait
  • Base64: atob, btoa
  • Web Crypto: crypto.getRandomValues, crypto.randomUUID, crypto.subtle.* (with support for MD5 digests and NODE-ED25519 signatures), crypto.DigestStream
  • Encoding: TextEncoder, TextDecoder
  • Fetch: fetch, Headers (including non-standard getAll method), Request, Response, FormData, Blob, File, URL, URLPattern, URLSearchParams (powered by undici)
  • Streams: ByteLengthQueuingStrategy, CountQueuingStrategy, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader (including non-standard readAtLeast method), ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, TransformStream, TransformStreamDefaultController, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, FixedLengthStream, CompressionStream, DecompressionStream
  • Events: Event, EventTarget, AbortController, AbortSignal
  • Event Types: fetch, scheduled, unhandledrejection, rejectionhandled
  • Misc: structuredClone, navigator

Subrequests

To match the behaviour of the Workers runtime, Miniflare limits you to 50 subrequests per request. Each call to fetch(), each URL in a redirect chain, and each call to a Cache API method (put()/match()/delete()) counts as a subrequest.

If needed, the subrequest limit to be customised using the MINIFLARE_SUBREQUEST_LIMIT environment variable. Setting this to a negative number disables the limit. Setting this to 0 disables subrequests.

$ MINIFLARE_SUBREQUEST_LIMIT=100 miniflare

Frozen Time

To match the behaviour of the Workers runtime, Miniflare will always return the time of last I/O from new Date() and Date.now().

This behaviour can be disabled by setting the actualTime option, which may be useful for performance testing. Note that the Miniflare ๐Ÿคน Jest Environment automatically enables this option.

$ miniflare --actual-time
wrangler.toml
[miniflare]
actual_time = true
const mf = new Miniflare({
actualTime: true,
});

Global Functionality Limits

To match the behaviour of the Workers runtime, some functionality, such as asynchronous I/O (fetch, Cache API, KV), timeouts (setTimeout, setInterval), and generating cryptographically-secure random values (crypto.getRandomValues, crypto.subtle.generateKey), can only be performed while handling a request, not in the global scope.

This behaviour can be disabled by setting the globalAsyncIO, globalTimers and globalRandom options respectively, which may be useful for tests or libraries that need async I/O for setup during local development. Note that the Miniflare ๐Ÿคน Jest Environment automatically enables these options.

$ miniflare --global-async-io --global-timers --global-random
wrangler.toml
[miniflare]
global_async_io = true
global_timers = true
glboal_random = true
const mf = new Miniflare({
globalAsyncIO: true,
globalTimers: true,
globalRandom: true,
});

KV namespaces and caches returned from Miniflare#getKVNamespace() and Miniflare#getCaches() are unaffected by this limit, so they can still be used in tests without setting any additional options.

instanceof, constructor and prototype Checks

Miniflare overrides instanceof checks for primitive classes like Object so they succeed for values created both inside and outside the Miniflare sandbox (in a different JavaScript realm). This ensures dynamic type checking often performed by WebAssembly glue code (e.g. wasm-bindgen) always succeeds. Note that values returned by Workers runtime APIs are created outside the Miniflare sandbox. See this file for more details.

Primitive classes in this case are defined as JavaScript built-ins that can be instantiated by something other than their constructor (e.g. literals, functions, runtime errors):

  • Object
  • Function
  • Array
  • Promise
  • RegExp
  • Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError

Primitive constructor and prototype checks cannot be trapped easily and so will fail for values created outside the Miniflare sandbox.

import { Miniflare } from "miniflare";
const mf = new Miniflare({
bindings: {
OBJECT: { a: 1 },
ARRAY: new Uint8Array([1, 2, 3]),
},
modules: true,
script: `
export default {
async fetch(request, env, ctx) {
console.log({ a: 1 } instanceof Object); // โœ… true
console.log(new Uint8Array([1, 2, 3]) instanceof Object); // โœ… true
console.log({ a: 1 }.constructor === Object); // โœ… true
console.log(Object.getPrototypeOf({ a: 1 }) === Object.prototype); // โœ… true
console.log(env.OBJECT instanceof Object); // โœ… true
console.log(env.ARRAY instanceof Object); // โœ… true
console.log(env.OBJECT.constructor === Object); // โŒ false
console.log(Object.getPrototypeOf(env.OBJECT) === Object.prototype); // โŒ false
throw new Error("oops!");
}
}
`,
});
try {
await mf.dispatchFetch("http://localhost");
} catch (e) {
console.log(e instanceof Error); // โŒ false
}

By default, primitive instanceof checks outside the Miniflare sandbox will fail for values created inside the sandbox (e.g. checking types of thrown exceptions in tests). To fix this, pass the primitive class in from Node.js as a custom global. Note this will cause primitive instanceof checks to fail for values created without the constructor inside the sandbox.

const mf = new Miniflare({
globals: { Error },
modules: true,
script: `
export default {
async fetch(request, env, ctx) {
throw new Error("oops!");
}
}
`,
});
try {
await mf.dispatchFetch("http://localhost");
} catch (e) {
console.log(e instanceof Error); // โœ… true
}