โ† All guides

A fetch-mock alternative when you need a real URL

Honest split first: fetch-mock earned its ~1.2 million weekly downloads. It has mocked fetch since before fetch was in Node, the modern fetchMock.mockGlobal().get(url, response) API is clean, and โ€” unlike some rivals' fake timeouts โ€” its { delay: 500 } option makes real time pass (we measured 509ms). For fast offline unit tests of fetch-based code it's still a fine choice. This page is not going to pretend otherwise.

First, the gotchas that send people searching

We verified all of these the week of writing (Aug 2026, fetch-mock v12.6.0, Vitest 4, Node 22) โ€” every snippet on this page was actually run:

If the process-boundary bullet is your actual problem, no in-process library fixes it โ€” the mock needs to be somewhere every client can reach:

The mock only exists inside your JS process

Mockbird is the other half: a hosted mock REST API on a real URL. Define resources (or pick a preset, or import an OpenAPI spec / db.json / CSV / Postman collection), get realistic seeded data and full stateful CRUD โ€” reachable from fetch, a browser, curl, a phone, another service, CI, or a teammate. No handler code, no version migrations, no signup.

The 60-second version

# one curl, no signup โ€” a whole seeded e-commerce backend
curl -X POST https://mockbird.mockbird.workers.dev/api/projects \
  -H 'content-type: application/json' -d '{"name":"shop","preset":"ecommerce"}'
# โ†’ {"id":"abc123","adminKey":"KEY", ...}   โ† save both

curl https://mockbird.mockbird.workers.dev/m/abc123/products?limit=3
# โ†’ 3 seeded products, CORS on, writes persist

Then in your app, nothing changes but the base URL:

const res = await fetch(`${process.env.API_URL}/products`);
// dev/test: API_URL=https://mockbird.mockbird.workers.dev/m/abc123
// prod:     API_URL=https://api.yourapp.com

Prefer clicking? This link creates the same project in your browser โ€” no account. Have an OpenAPI spec? Paste it at /app#import and get a live seeded mock of your actual API shape.

fetch-mock concepts โ†’ Mockbird

fetch-mock (v12)MockbirdNotes
fetchMock.mockGlobal()no code โ€” point the base URL at the mockno process boundary: subprocesses, curl, browsers, teammates all see the same mock
.get("/products", data)a products resourcelist/get/create/update/delete generated, plus filtering, sorting, pagination, relations
Hand-rolled response dataseeded realistic recordsfaker-style names/emails/prices/dates; or import your exact records from db.json/CSV
.get(url, { status: 500 })?mock_status=500 on any URLno handler edit โ€” error/loading states guide
.getOnce(url, 503) then .get(url, 200)?mock_seq=503,200deterministic per-caller sequences (add &mock_seq_key= to isolate parallel tests) โ€” retry logic sees real 503s then recovery
{ delay: 500 }?mock_delay=500both make real time pass (we measured; credit to fetch-mock here) โ€” plus ?mock_jitter=100-1500 and ?mock_chaos=0.3 random failures
callHistory.called(url) / .calls()request inspectorlast 50 requests: method, path, query, headers, body โ€” assert what was actually sent
removeRoutes() / clearHistory() between testssnapshot pinningsave named data states; each parallel test pins one via X-Mockbird-Snapshot โ€” no reset races
Unmatched call throwsn/a โ€” real endpoints answer real queriesany query composes: filters, ?select=, sort, pagination
unmockGlobal()flip the env var backyour app code never knew the difference

Try it in 10 seconds (shared demo, no setup)

# seeded data with field projection
curl 'https://mockbird.mockbird.workers.dev/m/demo/products?limit=2&select=name,price'

# the states you'd write handlers for โ€” as query params
curl -i 'https://mockbird.mockbird.workers.dev/m/demo/products?mock_status=503'
curl 'https://mockbird.mockbird.workers.dev/m/demo/products/1?mock_delay=2000'

# getOnce-style failure sequence, no handler: 503 then 200 then 200
curl -i 'https://mockbird.mockbird.workers.dev/m/demo/products?mock_seq=503,200&mock_seq_key=me1'

# stateful: the write persists (the thing handler code can't do for free)
curl -X POST https://mockbird.mockbird.workers.dev/m/demo/products \
  -H 'content-type: application/json' -d '{"name":"proof","price":9.99}'
# โ†’ returns {"id":31,โ€ฆ} โ€” and GET /m/demo/products/31 now works

All against the shared demo project (resets daily).

Or use both โ€” they compose (verified)

Honest comparison

fetch-mockMockbird
What it isfree OSS library (fetch only)free hosted service
Reachable fromthe JS process you call mockGlobal() inanything with HTTP: fetch, browser, curl, Postman, mobile, backend, CI, agents
Subprocesses / other clientsnot intercepted (verified: child process hit the real network)it's a real URL โ€” every client works by definition
Setupwrite + maintain handlers (across a v9โ†’v12 API break)one curl or one click; no code
Mock datayou write itseeded realistic data, or import your own
Stateful CRUDDIYdefault โ€” writes persist
Error/latency simulationper-handler; {delay} is real time (credit)?mock_status / ?mock_delay / ?mock_seq / ?mock_chaos / ?mock_jitter on any URL
Unmatched requestthrows (clear error, but every endpoint needs a handler)n/a โ€” real endpoints answer real queries
Works offlineyesno โ€” it's a real network call
Latencyzero (in-process)real network latency
Request assertionscallHistory, preciserequest inspector (last 50, with headers/body)
Version situationv12.6.0 current; 37% of installs still pin v9 (Nov 2020) โ€” npm registry, as of Aug 2026hosted โ€” nothing to pin or migrate
Request capnone10,000/project/day

Written by the Mockbird maker โ€” bias disclosed. Where fetch-mock genuinely wins: in-process interception means zero latency, zero network flakiness, tests that run on a plane; { delay } makes real time pass (unlike some rivals' instant fake timeouts); unmatched-call errors are loud and actionable; callHistory assertions are more precise than any log-based check; response functions are arbitrary JavaScript; and it's actively maintained โ€” v12.6.0 shipped with fresh @fetch-mock/jest and @fetch-mock/vitest wrappers. For offline unit tests of fetch-based code, keep it (on v12, with the new API). When the thing you need is a URL โ€” for a subprocess, a browser, a prototype, a teammate, a mobile client, or CI hitting a deployed build โ€” that's us.

Full API reference in the docs. More guides: mock API for Node.js ยท nock alternative ยท Polly.JS alternative ยท MSW alternative ยท axios-mock-adapter alternative ยท mock APIs in Jest ยท mock APIs in Vitest ยท free mock API tools compared ยท deterministic test data ยท testing loading & error states. Create your API โ†’