← All guides

A stubby4j alternative now that the repo is archived

Credit where due: stubby4j was a genuinely pleasant stub server. A single fat JAR, human-readable YAML stubs, three tidy portals (stubs on :8882, admin on :8889, TLS on :7443), --watch hot-reload, HTTP/2, WebSockets, regex-capture token replacement, even proxy record & replay. For a decade of Java integration suites it was the sane middle ground between hand-rolled fixtures and heavyweight service virtualization.

First, the elephant: the repo is archived

The GitHub repository was archived by its owner on June 28, 2025 β€” it is now read-only: no new issues, no pull requests, no fixes coming. The last release on Maven Central is 7.6.1, published February 8, 2024 (both checked August 2026). The sibling ports the README points to β€” stubby4node and stubby4net β€” live in a different author's repos and haven't been the answer for years either. If stubby4j is load-bearing in your test suite, you're now maintaining a fork or planning an exit.

WireMock is the usual Java-world exit ramp and it's a good one β€” see our WireMock Cloud notes for how its hosted tier prices out. This page is about a different exit: if what you were actually using stubby4j for is mocking a plain HTTP/JSON API β€” for a frontend, a mobile app, CI, or a teammate β€” you can stop maintaining stub files entirely.

What the YAML never gave you (each claim verified on 7.6.1, August 2026)

We downloaded the final 7.6.1 JAR from Maven Central and drove it with a plain config β€” a GET /products stub returning a canned list and a POST /products stub returning a canned 201. Observed behavior:

Wall 1: writes are theater. POST /products returned our canned 201 {"id":2,"name":"created"} β€” and the next GET /products returned the same one-widget list as before. Nothing was created; the 201 is a recording. There is no state to update β€” every "write" is a stub whose consequences you also stub.

Wall 2: query params match only exact stubbed values. stubby4j can match on query params β€” but only literally. Our GET /greet?name=ada stub answered name=ada with 200 and name=bob with 404. And a stub with no query block ignores params entirely: GET /products?page=2&limit=1 returned the same full canned body. Pagination, sorting, filtering β€” every variant is another YAML stanza, per resource, forever.

Wall 3: it's a localhost JVM process. The JAR binds local ports. The moment a teammate, a deployed preview, CI, or your phone needs the mock, you're provisioning and babysitting a server β€” and there was never a hosted stubby4j to upgrade to.

One honest point in stubby4j's favor: unmatched paths return a real 404 with a helpful x-stubby4j-http-error-real-reason header β€” better behavior than several tools we've tested that answer 200-empty.

The 60-second switch

Where you'd write a YAML file and launch java -jar stubby4j-7.6.1.jar -d stubs.yml, create a hosted project instead β€” nothing to run, no JVM:

curl -X POST https://mockbird.mockbird.workers.dev/api/projects \
  -H 'content-type: application/json' -d '{"name":"my-api"}'
# β†’ {"id":"g3cxybzbx3","adminKey":"…","baseUrl":"https://mockbird.mockbird.workers.dev/m/g3cxybzbx3",…}

curl -X POST https://mockbird.mockbird.workers.dev/api/projects/<PID>/resources \
  -H 'x-admin-key: <KEY>' -H 'content-type: application/json' \
  -d '{"name":"products","fields":[{"name":"name","type":"words"},{"name":"price","type":"price"}],"seed":5}'
# β†’ 5 realistic seeded records, live at /m/<PID>/products

Now the behaviors you'd hand-stub are just true:

# writes persist (ran against this API before publishing):
curl -X POST …/m/<PID>/products -H 'content-type: application/json' -d '{"name":"added by test","price":1.99}'
# β†’ {"name":"added by test","price":1.99,"id":6}
curl …/m/<PID>/products/6      # β†’ the same record. It's real.

# query params work with zero stanzas β€” any value, not just stubbed ones:
curl '…/m/<PID>/products?page=2&limit=3&sortBy=price&order=desc&price_gte=100'

# missing records are real 404s (stubby4j got this right; so do we):
curl -i …/m/<PID>/products/999  # β†’ HTTP 404 {"error":"not found"}

Have a fixed payload that really is best as a canned stub? Custom routes are one curl β€” any status, content type, headers, latency, and templating. stubby4j's regex-capture token replacement maps to named path params (we verified this exact route answered {"hello":"ada",…} before publishing):

curl -X POST …/api/projects/<PID>/routes -H 'x-admin-key: <KEY>' \
  -H 'content-type: application/json' \
  -d '{"method":"GET","path":"/greet/:name","status":200,
       "contentType":"application/json","body":"{\"hello\":\"{{params.name}}\",\"at\":\"{{now}}\"}"}'
curl …/m/<PID>/greet/ada   # β†’ {"hello":"ada","at":"2026-08-31T21:17:39.818Z"}

stubby4j concepts β†’ Mockbird

stubby4jMockbirdNotes
java -jar stubby4j.jar -d stubs.ymlPOST /api/projectshosted URL instead of :8882; nothing to run, no YAML file
- request:… response:… stanzacustom routemethod/path/status/body/headers/contentType/delayMs
canned CRUD stubsreal stateful resourcesPOST→GET-back persists; PUT/PATCH/DELETE; filters/sort/pagination/search built in
response: latency: 1500 (we measured 1.5 s)?mock_delay=1500per-request, no config edit β€” measured 2.4 s for mock_delay=2000 on the shared demo
response list on one URI (cycles: we observed 500,200,500,200…)?mock_seq=500,200semantics differ: ours plays the sequence once and the last value sticks (500,200,200…) β€” better for retry drills
error drills via extra stubs?mock_status=503, ?mock_chaos=0.3, ?mock_ratelimit=2any endpoint, on cue β€” guide
regex capture groups β†’ <% url.1 %> tokens/greet/:name β†’ {{params.name}}plus {{query.x}}, {{body.x}}, {{headers.x}}, {{now}}, {{uuid}}
admin portal :8889/statusrequest inspectorlast 50 requests with headers + bodies, readable from tests via API
admin portal POST API / StubbyClientmanagement REST APIeverything the dashboard does is a curl
--watch hot reloadedits are live instantlyserver-side persistence β€” there's no file to reload
proxy config / record & replayproxyBase + proxyRecordrecord a real API once, replay hosted β€” docs
TLS portal :7443, self-signed certHTTPS by defaultreal certificate, no -k flags in your tests
WebSockets stubbing (v7.6+)WS echo onlyhonest: scripted WS conversations have no equivalent here
HTTP/2 over TLS (h2)HTTP/2 by defaultCloudflare edge negotiates h2/h3 automatically
YAML in your reposnapshots + db.json exportsave/restore named data states; eject your data anytime

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

# query params that actually work β€” no YAML stanzas written:
curl 'https://mockbird.mockbird.workers.dev/m/demo/products?page=2&limit=3'

# latency-behavior equivalent, per request (measured 2.4s):
curl 'https://mockbird.mockbird.workers.dev/m/demo/products/1?mock_delay=2000'

# their cycling response list, as a one-shot retry drill:
curl 'https://mockbird.mockbird.workers.dev/m/demo/products?mock_seq=500,200&mock_seq_key=me1'
# β†’ 500 on the first call, 200 after

# writes persist β€” POST it, then GET it back:
curl -X POST 'https://mockbird.mockbird.workers.dev/m/demo/products' \
  -H 'content-type: application/json' -d '{"name":"from the stubby4j guide","price":1.99}'

Honest comparison

stubby4jMockbird
Pricefree, open source (MIT)free while in beta
MaintenanceGitHub repo archived June 28, 2025 (read-only); last release 7.6.1, Feb 2024actively developed
Hosted URL others can hitno β€” self-host a JVM processyes β€” 10,000 requests/project/day, no signup
Stateful CRUD (POST β†’ GET it back)no β€” canned responses only (verified 7.6.1)yes β€” persistent records, snapshots, restore
Query paramsexact stubbed values only; ignored if not stubbed (verified)pagination/filter/sort/search always on, any value
Unmatched pathreal 404 with diagnostic header βœ”real 404 with a JSON error
ProtocolsHTTP/1.1, HTTP/2, WebSockets stubbing, TLS portalHTTP(S) + GraphQL + SSE/WebSocket echo
Record & replay proxyingyesyes β€” proxyBase + proxyRecord
Works offlineyesno
Java in-process embeddingyes (StubbyClient, JUnit-friendly)no β€” it's a URL; see the Java guide

Written by the Mockbird maker β€” bias disclosed. Where stubby4j genuinely won: in-process JVM embedding for JUnit suites, scripted WebSocket conversations, offline use with no request caps, and YAML stubs that live in your repo and code-review cleanly. Every behavioral claim above was verified by us in August 2026 by running the final stubby4j-7.6.1.jar from Maven Central (stubs on :8882, admin on :8889, config as described); the archive date is from the GitHub repository banner; the release date is from Maven Central. If any of this changes, we'll update the page.

Full API reference in the docs. More guides: WireMock Cloud alternative Β· MockServer alternative Β· mountebank alternative Β· Hoverfly alternative Β· Karate mock server alternative Β· mock API for Java Β· mock API for Spring Boot Β· mock any custom endpoint Β· free mock API tools compared. Create your API β†’