Skip to content

Rift

High-performance Mountebank-compatible HTTP/HTTPS mock server written in Rust

Rift implements Mountebank's REST API and imposter format, so most existing imposters.json files and Mountebank clients work unchanged. It keeps its throughput flat as a stub file grows, and the same engine embeds in-process in Java, Node, Go and Scala.

Rift is compatible with Mountebank 2.9.5, the latest release (@mbtest/mountebank). Every pull request that changes the engine runs a differential suite that sends the same requests to a real Mountebank and to Rift. The differences it finds are listed in Differences from Mountebank. Compatibility is established by those tests, so behaviour they do not exercise can still differ: if you find a case, open an issue.

Rift, a Mountebank-compatible HTTP and HTTPS mock server. Requests reach an imposter and are checked against its stubs in order; the first stub whose predicates match answers with the next response in its cycle, 200 v1 and then 200 v2. A request no hand-written stub matches reaches a proxyOnce proxy stub, which forwards it upstream and records the answer as a new stub in front of itself; the next identical request is replayed from that recording without calling upstream.

Get Started View on GitHub


Why Rift?

Mountebank Compatible

Rift implements the Mountebank REST API, so you can usually:

  • load existing Mountebank configuration files without changes;
  • keep your current Mountebank clients and test tooling;
  • check the documented differences for anything your tests rely on.

Performance

Rift indexes stubs instead of scanning them in order, so its cost does not grow with the size of the stub file. Measured against Mountebank on the same machine:

Feature Mountebank Rift Speedup
Static stub (first match) 7,240 RPS 209,192 RPS 29x faster
Regex (100th pattern) 110 RPS 201,067 RPS 1,821x faster
JSONPath predicates 4,586 RPS 190,329 RPS 42x faster
API stub — no match (404) 1,376 RPS 204,358 RPS 149x faster
Complex predicates 4,884 RPS 185,867 RPS 38x faster

Apple M4 laptop, 50 connections, median of 3 repetitions, 2026-09-17. On a 16-vCPU AMD EPYC server the same suite reaches 325k RPS and 6,160x on regex — but Mountebank is slower there, so the M4 figures above are the conservative read.

See the performance page for both hosts, the full suite, and the method.

Mountebank Features

Rift supports Mountebank's HTTP and HTTPS feature set (not its TCP and SMTP protocols):

  • Imposters - HTTP/HTTPS mock servers on any port, including mutual TLS
  • Stubs - Request matching with responses
  • Predicates - equals, contains, matches, exists, jsonpath, xpath, and, or, not
  • Responses - Static, proxy, injection with behaviors
  • Behaviors - wait, decorate, copy, lookup, shellTransform
  • Recording - Proxy mode with response recording

And Then Some

Compatibility is the floor, not the ceiling. Rift adds the things you would otherwise build by hand on top of a mock server:

  • Fault Injection - probabilistic latency, error and TCP faults, declaratively
  • Scripting - Rhai and JavaScript engines, with a script check / script run CLI
  • Scenarios and Flow State - declarative state machines and a per-flow key/value store
  • Correlated Isolation - per-flow partitioning so parallel tests don't collide
  • Front Door and Gateway - route many imposters through one listener
  • Intercept Proxy - TLS-MITM a hard-coded external host without mitmproxy, over HTTP/1.1 or HTTP/2, with WebSocket upgrades relayed to the real origin
  • TLS & Mutual TLS - HTTPS imposters that require and validate client certificates, plus a private-CA trust store for proxying
  • Response Templates - date tokens and the _rift.templated {{ }} grammar, no script engine needed
  • Stub Analysis and Debug Mode - find shadowed stubs, and see why a request matched
  • Conditional GET and Vendor-Mock Templates - ETag / 304 without hand-synced validators, and ready-made mocks for third-party SaaS
  • Embedding & FFI - run the engine in-process from Rust or any language over the C ABI

The Features section covers all of them.


Quick Start

# Pull the latest image from Docker Hub
docker pull zainalpour/rift-proxy:latest

# Run Rift (Mountebank-compatible mode)
docker run -p 2525:2525 zainalpour/rift-proxy:latest

Create Your First Imposter

# Create an imposter that responds to GET /hello
curl -X POST http://localhost:2525/imposters \
  -H "Content-Type: application/json" \
  -d '{
    "port": 4545,
    "protocol": "http",
    "stubs": [{
      "predicates": [{ "equals": { "method": "GET", "path": "/hello" } }],
      "responses": [{ "is": { "statusCode": 200, "body": "Hello, World!" } }]
    }]
  }'

# Test the imposter
curl http://localhost:4545/hello
# Output: Hello, World!

Using an Existing Mountebank Config

# Start Rift with your existing imposters.json file
docker run -p 2525:2525 -v $(pwd)/imposters.json:/imposters.json \
  zainalpour/rift-proxy:latest --configfile /imposters.json

Node.js Integration

For Node.js projects, use the official npm package:

npm install @rift-vs/rift
import { rift, imposter, onGet, okJson, times } from '@rift-vs/rift';

await using engine = await rift.embedded(); // or rift.connect(url) / rift.spawn()

const users = await engine.create(
  imposter('users').stub(onGet('/api/users/1').willReturn(okJson({ id: 1, name: 'Alice' }))));

await fetch(`${users.url}/api/users/1`);
await users.verify(onGet('/api/users/1'), times(1)); // throws with a diff on mismatch

Migrating from Mountebank? The Mountebank-compatible rift.create({ port }) API stays available as a permanent drop-in, so adopting the typed DSL above is incremental rather than a rewrite.

See the Node.js Integration Guide for complete documentation.

Java / JVM Integration

For JVM projects, use the official rift-java SDK. It runs the engine three ways — embedded in-process (Panama FFM, no Docker), connected to any running admin endpoint, or as a managed spawned binary — with a fluent DSL plus JUnit 5, Spring, and Testcontainers integrations.

<dependency>
  <groupId>io.github.achird-labs</groupId>
  <artifactId>rift-java-core</artifactId>
  <scope>test</scope>
</dependency>
try (Rift rift = Rift.embedded()) {                  // or Rift.connect(uri) / Rift.spawn()
    Imposter users = rift.create(
        imposter("users").stub(onGet("/api/users/1").willReturn(okJson("{\"id\":1}"))));
    // point your system under test at users.uri(), then assert:
    users.verify(onGet("/api/users/1"), times(1));
}

See the rift-java documentation for the full feature surface, and the BOM for version-pinning every module at once.

Go Integration

For Go projects, use the official rift-go SDK. It runs the engine three ways — embedded in-process, connected to any running admin endpoint, or as a managed spawned binary — with a fluent DSL plus testing.T helpers.

The embedded transport loads the engine through purego rather than cgo, so CGO_ENABLED=0 keeps working: no C toolchain, and cross-compilation is unaffected.

go get github.com/achird-labs/rift-go
go run github.com/achird-labs/rift-go/cmd/rift-fetch@latest -version v0.24.0
func TestUserLookup(t *testing.T) {
    users := rifttest.Imposter(t, rift.NewImposter("users").
        Stub(rift.OnGet("/api/users/1").
            Return(rift.OKJSON(map[string]rift.JSON{"id": 1, "name": "Alice"}))))

    callSUT(t, users.BaseURL())

    rifttest.AssertReceived(t, users, rift.OnGet("/api/users/1"), rift.Once())
}

See the rift-go documentation for the full feature surface.

All four SDKs

Java, Scala, Node/TypeScript and Go are all officially supported and all replay the same conformance corpus. The Language SDKs section has the install snippet and hello-world for each, plus the transport and version-compatibility matrices.


Documentation

Getting Started

Concepts

Mountebank Compatibility (reference)

  • Imposters - Creating and managing mock servers
  • Predicates - Request matching (equals, contains, regex, jsonpath, xpath)
  • Responses - Configuring stub responses
  • Behaviors - Response modification (wait, decorate, copy, lookup, shellTransform)
  • Proxy Mode - Recording and replaying responses

Configuration

Features

Deployment

Reference

Embedding & Extension

  • Embedding & SPI - Embed Rift as a library, extend it via SPI traits
  • Embeddable Server - ServerBuilder, bindable admin/metrics
  • Extension Points (SPI) - Pluggable flow-store, journal, proxy store, sequencer, plus exchange-inspector, no-match, admin-authorizer and front-door observer hooks
  • FFI (C-ABI) - Drive Rift from any language

Project Status

The HTTP/HTTPS surface is stable and actively developed. Current status:

Area Status
HTTP / HTTPS imposters, including mutual TLS Stable
All predicates, static responses, behaviors Stable
Proxy mode (record & replay) Stable
JavaScript injection Stable
Fault injection, scripting (Rhai / JS) Stable
Scenarios, flow state, correlated isolation Stable
Front door, single-port gateway Stable
Intercept proxy (TLS-MITM, HTTP/2, WebSocket passthrough) Stable
Stub analysis, debug mode, hot reload Stable
Prometheus metrics, linting, terminal UI Stable
Embedding (Rust API, C ABI) and the four SDKs Stable
TCP protocol Not supported
SMTP protocol Not supported

License

Rift is distributed under the Apache License 2.0.