json-server is brilliant for local prototyping โ point it at a JSON file and you have a REST API. But the moment you need that API somewhere else, it gets awkward: your teammate has to clone and run it, your deploy preview can't reach localhost:3000, your phone can't test against your laptop, and CI needs yet another process to babysit.
Mockbird gives you the same conventions โ filters, sorting, pagination, _expand/_embed relations, nested routes โ as a hosted URL that exists in seconds. No install, no process to run, no tunnel. Anyone with the link gets the same data.
If you're migrating from json-server you don't want fake data, you want your data.
POST your db.json as-is and Mockbird hosts it:
curl -X POST https://HOST/api/projects/import --data-binary @db.json
Each top-level key becomes a resource, numeric ids are preserved, and nested
objects or arrays inside records are kept verbatim. The response gives you a
baseUrl โ swap http://localhost:3000 for it and your existing
?_page/?_sort/_expand calls keep working, plus you now
get a request inspector and webhooks.
Details and limits in the docs. Don't have a db.json handy?
Read on โ presets create a seeded backend from nothing.
No lock-in, ever: GET /m/<project>/db.json exports your
entire live dataset back in json-server's native format. curl -o db.json it and
npx json-server db.json runs the same API on your laptop โ try it on the demo:
curl -o db.json https://HOST/m/demo/db.json.
No signup needed. One curl creates a project with a whole blog backend โ posts, comments and authors, seeded with realistic fake data and linked by real foreign keys:
curl -X POST https://HOST/api/projects \
-H 'content-type: application/json' \
-d '{"name":"my-blog","preset":"blog"}'
The response gives you an id, an adminKey (keep it โ it's how you manage the project) and a baseUrl like https://HOST/m/abc123. That base URL is your API. Or skip curl entirely: the landing page has a one-click "try it" button and the dashboard does presets from a dropdown.
GET /m/abc123/posts # list, paginated, X-Total-Count header
GET /m/abc123/posts?page=2&limit=10 # pagination (_page/_limit work too)
GET /m/abc123/posts?sortBy=date&order=desc # or _sort/_order, json-server style
GET /m/abc123/posts?search=coffee # substring search (q= works too)
GET /m/abc123/comments?postId=3 # exact-match filter on any field
GET /m/abc123/posts?views_gte=100 # _gte/_lte/_gt/_lt/_ne range filters too
GET /m/abc123/posts?title_like=coffee # _like = case-insensitive substring
POST /m/abc123/posts # create โ next id assigned
PUT /m/abc123/posts/3 # replace
PATCH /m/abc123/posts/3 # merge
DELETE /m/abc123/posts/3
_expand, _embed, nested routes# each comment gains a "post" object (joined via its postId)
GET /m/abc123/comments?_expand=post
# a post with its comments attached
GET /m/abc123/posts/7?_embed=comments
# path-style, json-server classic:
GET /m/abc123/posts/1/comments # children of post 1
POST /m/abc123/posts/1/comments # creates with postId=1 set for you
Relations compose with filters, search, sorting and pagination, and work on list and single-record GETs alike.
| json-server (local) | Mockbird (hosted) | |
|---|---|---|
| Shareable URL | tunnel/ngrok required | built in โ it's just a URL |
| Deploy previews & CI | extra process | works from anywhere |
| Seeded realistic data | you write the JSON | 30+ faker-style field types, templates, presets |
| Failure simulation | โ | ?mock_delay=2000, ?mock_status=500 on any endpoint |
| OpenAPI spec | โ | live at /m/<project>/openapi.json |
| CORS | configure it | on by default |
The flag every frontend dev wants at 5pm: force the API to be slow or broken without touching code.
GET /m/abc123/posts?mock_delay=2000 # test your spinner
GET /m/abc123/posts?mock_status=500 # test your error state
GET /m/abc123/posts?mock_status=401 # test your auth redirect
Hit the "try it" button on the landing page โ you'll have a live seeded API before you finish reading this sentence. Anonymous projects can be claimed into an account later, so nothing you build is throwaway.