API & database emulation

Local emulators.
Real API contracts.

Mockingbird provides stateful emulators for third-party APIs and SQL databases. Use vendor-compatible request and response shapes, persistent in-memory state, and deterministic controls in Node, Bun, browsers, and Workers.

$
npm install -D @crvouga/mockingbird-service-stripe

Node.js · Bun · Browser · Workers

stripe.test.tsIn-process
import Stripe from "stripe"
import { createRuntime } from
  "@crvouga/mockingbird-service-stripe"

const emulator = createRuntime()

// Your Stripe SDK. Only its HTTP client changes.
const stripe = new Stripe("sk_test_mockingbird", {
  httpClient: Stripe.createFetchHttpClient(
    (url: string, init: RequestInit) =>
      emulator.fetch(new Request(url, init)),
  ),
})

const customer = await stripe.customers.create({
  email: "ada@example.com",
})
POST/v1/customers200 OK
Stateful runtime No external requests
125service emulators1638supported vendor operations
4JavaScript runtimes
01 / Before and after

A test environment with nothing outside it.

Tests that call live sandboxes wait on every vendor and fail when one is slow or down. Mockingbird runs an emulator of each service inside your process, so there is no network left to wait on.

beforeTests call live sandboxes
$ bun test checkout.test.ts
  1. charges the cardStripe480 ms
  2. texts the receiptTwilio1.2 s
  3. summarizes the orderOpenAI6.4 s
  4. posts to #ordersSlackretried2.9 s
  5. emails the invoiceResend730 ms
  6. stores the PDFAmazon S3timeout30.0 s
4 passed · 1 flaky · 1 failed41.7 s
afterTests call emulators, in process
$ bun test checkout.test.ts
  1. charges the cardStripe2 ms
  2. texts the receiptTwilio1 ms
  3. summarizes the orderOpenAI3 ms
  4. posts to #ordersSlack1 ms
  5. emails the invoiceResend2 ms
  6. stores the PDFAmazon S33 ms
6 passed12 ms
The same tests in both runs. Timings are illustrative.
02 / Quick start

From product data to a paid order.

Build a checkout with PostgreSQL and Stripe emulators. Seed the data, write an API against the unmodified Stripe SDK, and place an order from a client. Every step runs in your process.

$
npm install -D @crvouga/mockingbird-service-postgres @crvouga/mockingbird-service-stripe
data.tsTypeScript

Seed a product catalog and an orders table in the PostgreSQL emulator.

TypeScript
import { Database } from "@crvouga/mockingbird-service-postgres"

export const db = new Database()

db.exec(`
  CREATE TABLE products (id text PRIMARY KEY, name text, price integer);
  CREATE TABLE orders (id text PRIMARY KEY, product_id text, payment_id text);

  INSERT INTO products VALUES ('starter-kit', 'Developer starter kit', 2900);
`)

// Real SQL, in memory. No database server to configure.
console.log(db.query("SELECT name, price FROM products"))
// [{ name: "Developer starter kit", price: 2900 }]
201 CreatedPayment confirmed. Order saved.Zero network requests

Save all three files next to the stripe SDK your app already has, then run bun client.ts or npx tsx client.ts. Follow the walkthrough

03 / Runtime controls

Reproducible behavior, with explicit coverage.

Emulate the operations your application uses, inspect supported behavior, and control state between runs.

The vendor's real surface

Each emulator answers the provider's own paths, headers, status codes and error envelopes through fetch(Request) → Response. Point the official SDK at it.

State that behaves

Records persist in an in-memory SQL engine. Created customers can be listed, orders move through their lifecycle, webhooks fire, and reset or snapshot takes one call.

Checked against the real thing

Random walks generated from each vendored OpenAPI contract run against two emulator instances in CI, and against the live sandbox when credentials exist.

No network, no waiting

Everything runs in your test process. No sandbox keys, rate limits, shared test accounts or flaky round trips.

Runs anywhere JavaScript runs

Every emulator is isomorphic: the same package runs in Node, Bun, browsers, and Workers. The playgrounds on this site run that package in your browser tab.

One set of controls for every service

Every HTTP emulator takes the same admin controls: isolation by key, reset, snapshot and restore, time travel, faults, latency and timeouts, all replayed from a seed. Set them at boot, through /__admin, or in a request header.

04 / Admin controls

Put any emulator in any state. Then do it again.

Every HTTP emulator answers the same admin controls. Isolate state by key, reset it, snapshot and restore it, move the clock, and inject faults, latency and timeouts. Each one is a field in a single document that means the same thing at boot, over /__admin, and in a request header, and all of it replays from a seed.

stripe.test.tsAt boot
const stripe = createRuntime({
  seed: 7,
  adminControls: {
    clock: {
      now: "2030-01-01T00:00:00Z",
      frozen: true,
    },
    latency: "40ms",
    faults: [{ preset: "rate_limited" }],
  },
})
terminalOver /__admin
curl -X POST :8787/__admin/snapshots \
  -d '{"name": "base"}'
curl -X POST :8787/__admin/clock \
  -d '{"advance": "15m"}'
curl -X POST :8787/__admin/faults \
  -d '{"status": 503, "count": 2}'
curl -X POST :8787/__admin/snapshots/base/restore
requestIn a request header
POST /v1/charges
x-mockingbird-namespace: worker-3
x-mockingbird-time: 2030-01-01T00:00:00Z
x-mockingbird-fault: status=503; delay=2s

Isolation by key

x-mockingbird-namespace: worker-3 gives a request its own records, clock, random streams, faults, latency, journal and snapshots. Parallel workers share one process and never see each other.

Interface

Reset

POST /__admin/reset returns a namespace to its boot state: seed data, clock, faults and ids. A reset namespace cannot be told apart from a new one.

Interface

Snapshot and restore

POST /__admin/snapshots captures records, the clock, the random streams and the fault counters. Restore it, export it as JSON, commit it, or boot another process from it.

Interface

Time travel

Freeze the clock, set it, or advance it by 15m. Expiries and retry windows arrive in milliseconds. Read state as it was at any checkpoint, or branch from one.

Interface

Faults

Answer 503, drop the connection, or cut a response off mid-body. Match by operation, path or header; fire on the third request, every fifth, for the next five minutes, or at a seeded rate.

Interface

Latency and timeouts

Give every response a delay with seeded jitter, or make one request hang. With virtualTime the wait is spent on the mock clock, so a thirty-second timeout costs no test time.

Interface

Deterministic, down to the journal

The same seed and the same requests give the same bytes: ids, timestamps, which requests a rate fault hits, and the request journal. Reset and restore rewind the random streams with the state, so a test passes or fails the same way whether it runs first or last, alone or beside forty workers.

Admin controls guide
05 / Emulator catalog

Find your application's dependencies.

All 125 emulators
06 / Interactive example

A complete application, running in your browser.

The client, server, database emulator, and API emulators share one browser tab. Explore the application and its state without configuring a server.

ClientLab workspace UI
ServerHTTP API
  • OAuthGoogle & Apple sign-in
  • JunctionLab results
  • StripePayments
  • PostgreSQLDatabase
Everything above runs in this tab. No request leaves it.
  • Run it in this tab, with nothing to install
  • Serve it with bun run dev behind a real port
  • Test it with bun test, routes driven in-process
How it's built
Lab ordering workspaceRunning in this tab · no server required

07 / Service interface

A shared control plane for every HTTP emulator.

Every HTTP service ships an in-process fetch, a Node server and a CLI, and all answer the same control surface, so a stack learns it once. Every internal path is under /__admin by default. Set adminPrefix or serve --admin-prefix (MOCKINGBIRD_ADMIN_PREFIX) to relocate the entire tree; /health and /ns aliases are removed.

InterfaceBehavior
createRuntime() · createServer() (./server) · mockingbird-<service> serveThe emulator as one runtime-neutral fetch, or a listening server from Node or the CLI
GET /__admin/healthUnauthenticated readiness probe, outside the vendor's auth gate
/__admin/* (x-mockingbird-admin-key optional)The admin controls: reset, snapshot and restore, clock, faults, latency, a request journal, metrics with unmatched-route counts, plus service-specific routes. GET /__admin lists every route and header
GET /__admin/stateThe collections in the selected namespace: declared shape, live Collection fields, and stored rows. Create, replace, merge, and delete records through the same paths on every emulator
GET /__admin/uiThe shared admin UI. An emulator can add panels or replace the document; the shell still reads the same state API. Its header fetches that service's logo, website, and docs from the docs site when the page opens
x-mockingbird-namespacePer-request isolation: parallel workers share one process without sharing data, clocks, faults or ids
adminControls · --admin-controls · x-mockingbird-*The same control document at boot, on the command line, and in request headers
--seed, a frozen clock, virtualTimeSeeded randomness, a clock that moves only when told to, and waits that cost no time, so a run replays byte for byte
--log jsonOne structured line per request: operation id, status, duration, namespace, fault

mockingbird.json names services by their package suffix. HTTP services, PostgreSQL and Redis share a supervisor with ephemeral ports, readiness discovery and namespace controls. Use --ready-file or --ready-json to discover endpoints; see Fleets. SQLite remains an in-process engine.

Machine-readable documentation

Source-backed guides for developers and agents.

Every npm package ships an agent index at node_modules/<package>/DISCOVERY.md. It points to the local behavior guide, exact capability matrix, machine-readable contract or compatibility evidence, public types, parity oracle, runtime introspection, and issue-reporting contract. llms.txt indexes those files with the parity each service declares, and the docs site publishes the same source material as markdown and JSON. When an emulator diverges from the real API, lacks a feature you call, or the vendor you need is not in the catalog, file an issue: the filing guide gives the title format, templates and the behavior spec for feature and service requests.

↑↓ to navigate↵ to open