โ† All guides

A @graphql-tools/mock alternative โ€” when the GraphQL mock needs to be a URL

Let's start with the respect it's owed: @graphql-tools/mock is the standard way to mock GraphQL in JavaScript โ€” 1.36 million downloads a week (npm, Aug 19โ€“25, 2026), maintained by The Guild, and it's what Apollo Server's own mocking documentation tells you to use. The core move is genuinely great: hand addMocksToSchema an executable schema and every resolver is auto-mocked from the type system. For schema-first unit tests inside a JS process, it is the right tool, full stop.

But if you're on this page, you've probably hit the moment where the mock needs to leave your process โ€” and that's the wall it can't cross, plus a few smaller ones that cost real time. We verified everything below against v9.1.13 in August 2026 by running it.

The walls (all reproduced, v9.1.13)

1. The mock only exists inside your JS process. addMocksToSchema returns a schema object. Unless you also stand up and operate an HTTP server around it, there is no URL โ€” curl, Postman, your Flutter/iOS/Android app, a backend service in another language, a teammate on another machine, and CI running against a deployed preview all get nothing. And if you do wrap it in a yoga/apollo-server instance, you now own hosting, uptime, and state for a mock server.

2. Default data is unusable for anything demo-shaped. Out of the box, every String field is literally "Hello World", every Float is a random number that can be negative, and every list has exactly 2 items. Our actual first query:

{ products { id title price inStock } }
// โ†’ [{ "title": "Hello World", "price": 54.243850259423, ... },
//    { "title": "Hello World", "price": -85.07702399873587, ... }]
//   a product priced at -85.08, named Hello World โ€” for every product

Fixable, sure โ€” by writing and maintaining a mock function per scalar and per type. That's mock config as code, forever.

3. Mutations ignore your arguments by default. This one surprises everyone the first time:

mutation { createProduct(title: "X") { id title } }
// โ†’ { "title": "Hello World" }   โ† your argument went nowhere

4. Statefulness is DIY โ€” and the wiring is subtle. The MockStore can hold state, but you must write resolvers for it, and here's the gotcha we hit: wiring only the mutation through the store isn't enough โ€” store.set(...) in the mutation silently doesn't round-trip until the query field is also resolved from the store:

const mocked = addMocksToSchema({ schema, resolvers: (store) => ({
  Query:    { product: (_, { id }) => store.get('Product', id) },  // โ† required too!
  Mutation: { setTitle: (_, { id, title }) => {
    store.set('Product', id, 'title', title);
    return store.get('Product', id);
  }},
})});

With both wired it works โ€” and it's still in-memory in one instance. New process, new test file, teammate's machine: amnesia.

5. You need the SDL first. The library mocks a schema you already have and maintain. If what you actually have is a db.json, a CSV, an OpenAPI spec, or just a list of resources, the SDL is another artifact to write.

The hosted version of the same idea

Mockbird starts from data instead of SDL: define resources (or import an OpenAPI spec, db.json, or CSV), get realistic seeded records (faker-style names, prices, emails โ€” never "Hello World", never a negative price), and a hosted GraphQL endpoint is generated from them โ€” typed schema, introspection, GraphiQL when you open the URL in a browser. Mutations persist for real, no resolver wiring. This transcript ran against the shared demo project before publishing:

# arguments are honored (limit, sortBy, order, typed where filters):
curl https://mockbird.mockbird.workers.dev/m/demo/graphql \
  -H 'content-type: application/json' \
  -d '{"query":"{ products(limit: 2, sortBy: \"price\", order: \"desc\") { id name price inStock } productsCount }"}'
# โ†’ 2 top-priced products + "productsCount": 30

# mutations take input and PERSIST:
#   mutation { createProduct(input: { name: \"Guide check\", price: 12.5 }) { id } }  โ†’ id 31
#   { product(id: 31) { name } }        โ†’ "Guide check"
#   REST GET /m/demo/products/31        โ†’ the same record โ€” one store, two protocols
#   mutation { deleteProduct(id: 31) }  โ†’ true; product(id: 31) โ†’ null

The URL is the whole point: paste it into a mobile app, a Go service, a teammate's Slack, a Playwright config on CI, a deployed preview's env var. Nobody installs anything.

@graphql-tools/mock concepts โ†’ Mockbird

@graphql-tools/mockMockbirdNotes
hand-written SDL + makeExecutableSchemaresources with typed fieldsschema generated for you; or import OpenAPI / db.json / CSV
mock function per scalar/type ("Hello World" defaults)30+ field types, realistic seedsno per-type mock code to maintain; no LLM involved
MockStore + resolver wiring for statemutations just persistbacked by a real database; REST and GraphQL share it; webhooks fire
in-memory, per-instance statepersistent across requests/machinessnapshots save/restore named data states
one store per test workersnapshot pinning per requestX-Mockbird-Snapshot: empty โ€” parallel workers, zero races
list length via mock config (default: always 2)real record counts?seed=200 at create time; productsCount is honest
error simulation via throwing resolvers?mock_status, ?mock_chaos, ?mock_delayworks on the GraphQL endpoint too โ€” test retry/timeout paths from any client
schema exists only in JShosted URL + exportsopenapi.json, types.ts / Zod, Postman collection generated from the same source
preserveResolvers partial mocking of a real schemano equivalenthonest: mixing real resolvers with mocks is theirs alone

Use both โ€” they compose

This isn't either/or. Keep @graphql-tools/mock for fast, offline unit tests of resolver-level logic. Point everything that needs a network at a Mockbird URL: integration tests, deployed preview environments, the mobile team, demos, and any client that isn't JavaScript. One pattern we like: the component test suite runs against addMocksToSchema in-process, and the same queries run in CI against a Mockbird project pinned to a named snapshot โ€” ephemeral per-workflow-run mock APIs make that a 3-line job step.

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

# GraphiQL in your browser:
#   https://mockbird.mockbird.workers.dev/m/demo/graphql

curl https://mockbird.mockbird.workers.dev/m/demo/graphql \
  -H 'content-type: application/json' \
  -d '{"query":"{ products(limit: 2) { id name price } }"}'

# same data over REST:
curl 'https://mockbird.mockbird.workers.dev/m/demo/products?limit=2'

Or create your own: one-click ecommerce project โ€” the GraphQL endpoint is at /m/<your-project>/graphql immediately.

Honest comparison

@graphql-tools/mockMockbird
Pricefree, open source (MIT)free while in beta
Where the mock livesinside your JS processhosted URL, any client
Schema shapesany SDL โ€” unions, interfaces, custom scalars, arbitrary nestinggenerated from resources (flat-ish types + relations); no SDL import
Default data"Hello World", random floats, lists of 2realistic seeded records
Stateful mutationsDIY resolver + store wiring, in-memorybuilt in, persistent
Custom resolver logicarbitrary JS โ€” anything you can codefixed semantics + custom routes with templating
Partial mocking of a real schemayes (preserveResolvers)no
Works offline / zero latencyyesno
Request capsnone10,000 req/project/day free
Non-JS clients, teammates, CI-vs-previewno (unless you host a server yourself)the whole point
Maintenanceactively maintained (The Guild)actively developed

Written by the Mockbird maker โ€” bias disclosed. Where @graphql-tools/mock genuinely wins: it mocks your exact SDL including unions, interfaces, and custom scalars โ€” Mockbird cannot host an arbitrary hand-written schema shape today; preserveResolvers lets you mock only part of a real schema, which has no equivalent here; resolver mocks are arbitrary JavaScript; and it runs offline with zero network latency and no caps. Every claim above was verified by us in August 2026: the "Hello World" / negative-price / lists-of-2 / arguments-ignored transcripts come from running v9.1.13 locally (graphql 16.x), the store-wiring gotcha from our own working repro, the download count from npm's public API for the Aug 19โ€“25, 2026 week (1,361,661), and the Mockbird transcript from the live demo project before publishing. If any of this changes, we'll update the page.

Full GraphQL reference in the docs. More guides: free GraphQL mock API ยท graphql-faker alternative ยท json-graphql-server alternative ยท MSW alternative ยท deterministic test data ยท free mock API tools compared. Create your API โ†’