Local-first API client + mock server

Stub it. Ship it.

StubHouse is the desktop API client that takes mocking seriously. Native, offline, file-based — built for the developer who has to ship before the API exists.

Available for macOS, Linux, and Windows.

Native Rust core Offline workspaces Mock server included
StubHouse — my-project
GET https://api.example.com/users

Response

// Open workspace

One workspace for real requests, local mock rules, scenarios, and recorded fixtures.

Two tools. One binary.

A request client and a mock server, both first-class.

Other API clients bolt on mocks as a paid afterthought or a separate process. StubHouse was built around the assumption that you spend half your day calling APIs and the other half pretending an API exists. Both deserve a real tool.

Request — production

GET · https://api.example.com/users

200 OK · 132 ms
{
  "items": [{ "id": "u1", "name": "Ada" }]
}
Mocks — rules
  • GET /users success
  • POST /users success
  • GET /users/:id not_found

Scenario dropdowns live next to the routes they own.

Source of truth

Your API definitions live in a folder you own.

No proprietary database. No cloud account required. A workspace is a `.stubhouse/` directory of YAML files: requests, mock rules, environments, scripts. Commit it to git. Diff it in PRs. Move it between machines with `cp -r`. The tool builds on top of files; the files outlive the tool.

.stubhouse/collections/users/get-user.yaml yaml
id: req_get_user
name: "Get User by ID"
description: |
  Retrieves a single user by their unique ID.
method: GET
url: "{{base_url}}/users/{{user_id}}"
headers:
  - key: Authorization
    value: "Bearer {{auth_token}}"
    enabled: true
auth:
  type: bearer
  token: "{{auth_token}}"
tags:
  - users
  - read

The mock server

Three things worth doing in-process.

Scenarios

Switch your mock from `success` to `not_found` to `server_error` without restarting anything. From the UI, from the CLI, or from your test runner via the control API.

200 · synthetic output

{
  "id": "{{params.id}}",
  "name": "Alice Nguyen",
  "email": "alice@example.com"
}

Stateful mocks

A mock that behaves like an API. POST creates. PUT updates. DELETE removes. GET returns what you wrote. All in memory, all reset on demand.

.stubhouse/collections/users/mocks/resources.yaml yaml
mock_resources:
  - path: /users
    id_field: id
    seed_file: ./fixtures/users.yaml
    auto_crud: true
curl -X POST http://127.0.0.1:4000/users -d '{"name":"Ada"}'
curl http://127.0.0.1:4000/users/usr_1
curl -X DELETE http://127.0.0.1:4000/users/usr_1

Recording mode

Point StubHouse at a real API. Make some calls. Save them. Replay them offline. Forever.

Upstream

Traffic passes through to the real service while rules are captured.

Chaos, on demand

Test the unhappy path before production does.

Connection resets. Timeouts. Slow responses. Partial bodies. Random 5xx at a configurable rate. Every fault is a checkbox. Your retry logic finally has something to retry against.

connection_reset

TCP reset mid-response — exercise reconnect paths.

fault: connection_reset

timeout

No reply until the client gives up.

fault: timeout

slow_response

Fixed or random tail latency.

delay_ms:
  type: random
  min: 800
  max: 3000

partial_body

Truncated payloads for parser hardening.

fault: partial_body

random_5xx

Rare server errors on demand.

fault:
  type: random_5xx
  probability: 0.12

passthrough

Forward to upstream when you need a real edge.

passthrough: true

Automation, sandboxed

Logic that doesn't need a Node.js runtime.

StubHouse uses Rhai — a sandboxed scripting language designed for embedding in Rust. Pre-request scripts. Post-response assertions. Mock rule conditions. All run in a sandbox with no filesystem, no network, no escape. No 50MB V8 binary in your dock.

tests.rhai rhai
test("Status is 200")        { response.status == 200 }
test("Body has user field")  { response.json()["user"] != null }
test("Response under 500ms") { response.time_ms < 500 }
Test runner

Status is 200 · pass · 4 ms

Body has user field · pass · 1 ms

Response under 500ms · pass

It's a binary

stubhouse serve and ship.

The same engine that runs in the desktop app runs from the command line. Spin up your mocks in CI. Run your assertion suite against them. Get JUnit XML out the other side. Ten kilobytes of YAML replaces a thousand lines of `nock`.

ci.sh bash
# CI: serve mocks, run tests, switch scenario
stubhouse serve . --port 4000 --env test &
MOCK_PID=$!

npm test

stubhouse scenario set mock_payment checkout_failure
npm test -- --grep "error handling"

kill $MOCK_PID

Honestly

Where StubHouse fits.

A direct comparison with the tools you already know. We ship the embedded mock as part of the product, not as an upsell.

StubHousePostmanInsomniaBrunoYaak
Local-first (no account)
Files as source of truth
Embedded mock server
Stateful mocks
Scenario switching
Recording mode
Fault injection
Mock control API
CI / headless mode
OpenAPI schema validation
Native binary (no Electron)
Scripting languageRhaiJS (V8)JS (V8)JS (V8)
Free and open source

Local-first (no account)

StubHouse Postman Insomnia Bruno Yaak

Files as source of truth

StubHouse Postman Insomnia Bruno Yaak

Embedded mock server

StubHouse Postman Insomnia Bruno Yaak

Stateful mocks

StubHouse Postman Insomnia Bruno Yaak

Scenario switching

StubHouse Postman Insomnia Bruno Yaak

Recording mode

StubHouse Postman Insomnia Bruno Yaak

Fault injection

StubHouse Postman Insomnia Bruno Yaak

Mock control API

StubHouse Postman Insomnia Bruno Yaak

CI / headless mode

StubHouse Postman Insomnia Bruno Yaak

OpenAPI schema validation

StubHouse Postman Insomnia Bruno Yaak

Native binary (no Electron)

StubHouse Postman Insomnia Bruno Yaak

Scripting language

StubHouse Rhai Postman JS (V8) Insomnia JS (V8) Bruno JS (V8) Yaak

Free and open source

StubHouse Postman Insomnia Bruno Yaak

Sourced from public information as of 2026-05-08. Updated when competitors ship. Corrections welcome — open a PR.

Under the hood

Native binary. No Electron.

Tauri 2 shell. Rust core. `hyper` HTTP runtime. `rustls` for TLS. Embedded mock server runs in a Tokio task in the same process as the UI. Numbers below are illustrative until we publish measured builds beside shipping artifacts.

StubHouse
~25 MB
Insomnia
~110 MB
Postman
~350 MB

Cold-start bar uses the same discipline — measure before launch, publish with releases.

It's free. It's open.

MIT licensed.

StubHouse is open source under the MIT License. No usage tracking. No telemetry without an explicit opt-in. No "Pro" features held hostage. The full source — desktop app, CLI, and core libraries — is on GitHub. PRs welcome.

terminal bash
$ git clone https://github.com/stubhouse/stubhouse
$ cd stubhouse && cargo build --release
   Finished release [optimized] target(s) in 2m 14s

Ready when the API isn't

Run real requests and local mocks from one native app.

Free, open source, and available for macOS, Linux, and Windows.