v1 has been at beta.15 since March, and singular resources have no POST
Project brief: Get a full fake REST API with zero coding in less than 30 seconds (seriously).
At a glance
- What is it?
- JSON Server turns a JSON file into a REST API with conditions, sorting, pagination, embedding and static file serving, and the v1 rewrite is a large one. The mechanics are worth reading in package.json rather than the README: the manifest lists small dependencies such as milliparsec, dot-prop, sort-on and inflection, development needs Node's type-stripping flag, and the routes table quietly omits POST and DELETE for singular object resources.
- Who is it for?
- JSON Server suits a front-end developer who wants a working API in the next minute, because a JSON file in, a REST surface out, with conditions, sorting, pagination and relation embedding, needs no code and no schema definition.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 7 months ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- typicode/json-server75,743 ★ · +62
| Repository | 2026-08-04 | 2026-11-13 |
|---|---|---|
| typicode/json-server | 75.7k | 75.7k |
62 Stars in the last 101 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
v1 is still beta.15, and the last commit was 2026-03-23
The README opens with a callout rather than a description, and it says this is beta v1 documentation, usable but with expected breaking changes, and points to the v0.17.4 tree for the stable version. The package manifest agrees: the version field reads 1.0.0-beta.15.
The release list shows how that has gone. v1.0.0-beta.13 was published on 2026-03-13, beta.14 on 2026-03-20 and beta.15 on 2026-03-23, and the last push to the main branch was on 2026-03-23, the same day. The repository is not archived. So the three most recent tags are all pre-releases of a 1.0 that has not landed, they landed within about ten days of each other, and nothing has been committed since.
The consequence is a choice with no comfortable default. A 1.0 that has been in beta for as long as this one, with no commits since its last tag, is a rewrite whose remaining work is not visible from here. You are choosing between a line that is older and stable, and a line that is newer and unfinished, and both are described in the same repository.
A singular object resource has no POST and no DELETE
The routes table is split in two, and the second half is much shorter. Array resources such as `posts` and `comments` get the full set: GET on the collection, GET on an id, POST, PUT on an id, PATCH on an id and DELETE on an id.
Object resources, described as singular and exemplified by `profile`, get three routes only:
GET /profile
PUT /profile
PATCH /profileThere is no POST and no DELETE. You can read a singleton and you can overwrite or patch it, but you cannot create one and you cannot remove one through the API.
For a mock that is a real gap rather than a detail. A `profile` object in the example database models the kind of record a real application would create on signup and delete on account closure, and neither of those operations is available. A front-end flow that posts a new singleton and then tears it down has to be faked at a different layer, or modelled as a single-element array instead, which changes the URL shape your client code is written against.
Note that this is about the HTTP surface, not the file. The JSON on disk can hold a `profile` with no name, and you can edit the file directly. It is the API that will not do it.
ids became strings, _limit became _per_page, _expand became _embed
The README carries a migration section for v0 to v1, and the entries are behavioural rather than cosmetic.
Ids are the one with teeth. In v1, `id` is always a string and is generated automatically when you do not provide one. Your example database has numeric-looking ids, `"id": "1"`, written as strings already, so a v0 fixture with real numbers comes back as strings after the upgrade, and any client code that compares an id with `===` against a number stops matching. A trailing note also says that request delays are no longer configured the old way.
Two parameters are renamed rather than changed. `_limit` is deprecated in favour of `_per_page` used with `_page`, and `_expand` is replaced by `_embed` for including related resources. Both old names are plausible to guess, so a query string carried over from v0 either stops filtering or starts ignoring the relation, depending on which one you missed.
The README also documents `_dependent` on a delete, which cascades.
DELETE /posts/1?_dependent=commentsDeleting a post that still has comments attached is the case this covers.
Development needs Node's type-stripping flag, and installing the package does not
The manifest pins the runtime: engines requires node >=22.12.0. The reason is visible in the scripts, where `dev` and `test` both run Node with `--experimental-strip-types` and point at the TypeScript sources directly, for example `node --watch --experimental-strip-types src/bin.ts fixtures/db.json` for development and `node --experimental-strip-types --test src/*.test.ts` for the suite.
The published package is different. The build script is `rm -rf lib && tsc`, meaning the whole output directory is deleted and recompiled with no incremental step, and the files array ships `lib`, `views` and `schema.json` and nothing else. So what lands in node_modules is compiled JavaScript, and the type-stripping flag is a contributor-only requirement that the one-line install never mentions.
That gap has a practical consequence. Someone on an older Node may not realise that the floor is 22.12.0. The floor is only visible in the manifest, not in the quick start.
Two other choices in the scripts are worth knowing. Linting and formatting are `oxlint` and `oxfmt` rather than the eslint and prettier pair, and there is a `prepare` script running husky, so a clone installs git hooks.
Bad pagination values are clamped into range instead of rejected
Pagination is two parameters, and the defaults are documented: `_per_page` defaults to `10` if not specified. The response is not a bare array but an envelope carrying `first`, `prev`, `next`, `last`, `pages`, `items` and a `data` array.
The line to note is the last note under it, which says that invalid `_page` or `_per_page` values are automatically normalized to valid ranges.
So a client that sends `_page=abc`, or `_page=-4`, or `_per_page=0`, has the values quietly pulled into a legal range, since the README says invalid values are automatically normalized.
That is a deliberate kindness with a debugging cost. A pagination bug in a front end, a zero-indexed assumption where one-based is expected, a variable that arrives as the string `undefined`, all of them produce a working response and a list that looks plausible but is not the list the code meant to fetch. A test asserting on page contents will pass while the paging logic is wrong, and the only place the difference shows is the `pages` and `last` fields versus what the component expected.
The same forgiving posture shows up elsewhere. `_where` takes a JSON object and overrides the ordinary query parameters when it is valid, and the condition operators include case-insensitive `contains`, `startsWith` and `endsWith` alongside the numeric comparisons and `in`.
The query language is the dependency list, read one package at a time
There is no query engine in the manifest, just small pieces.
The manifest lists `milliparsec`, `dot-prop`, `sort-on` and `inflection` as small utility dependencies; the README does not say how each is used. `lowdb` is the persistence layer over the JSON file, and `chokidar` is what makes the server notice when you edit that file while it is running. The HTTP layer is `@tinyhttp/app` with its cors and logger add-ons rather than Express, and `sirv` handles the static files. `eta` is a template engine, `chalk` colours the startup output, and `json5` is what lets the same database be written as `db.json5` with unquoted keys and trailing commas.
Knowing that list explains the limits of the query language. The operators you get are the ones the README lists, and there is no documented hook for adding your own. Nesting works through dot paths, so a deeper object is addressable, but nothing in the manifest suggests arbitrary expressions, and `_where` is the one escape hatch, taking a JSON object and overriding the normal parameters when it parses.
The startup line is the quickest confirmation you are in the right place, printed as `JSON Server started on PORT :3000`.
Everything in ./public is served, and no authentication is described
Static file serving is on by default. The README states that JSON Server automatically serves files from the `./public` directory, and that additional directories can be added with the `-s` flag, for example:
json-server db.json -s ./static
json-server db.json -s ./static -s ./node_modulesFiles are served with standard MIME types, and the intent is obvious: put a front-end build next to the mock and the whole thing is one process. The tree is arranged for it, with a `public` directory, a `views` directory that the published package includes, and a `fixtures` directory holding the database the development script runs against.
The routes table shows no login, API key or per-route permission. The database file is the entire state, and the API reads and writes it directly.
For a development tool on a laptop that is the correct design, and the startup output points at `http://localhost:3000`. The risk is what happens when the port is reachable from somewhere else, and nothing in the README or the manifest marks that boundary. Mount a directory with `-s ./node_modules` and you have published your dependency tree to anything that can open a socket. Treat the port as loopback-only and treat any exposure of it as publishing your fixtures, because that is what the server is doing.
Editorial conclusion
JSON Server suits a front-end developer who wants a working API in the next minute, because a JSON file in, a REST surface out, with conditions, sorting, pagination and relation embedding, needs no code and no schema definition. It does not suit anyone treating it as a service, since it is a development fixture with no authentication described, and it does not suit a team that has already standardised on the 0.x behaviour without reading the migration notes, because ids change type and two query parameters are renamed. Before you commit, check which line you are on: v1 was still beta.15 when the last commit landed on 2026-03-23, and the stable line the README points to is v0.17.4, so the two behave differently on ids, pagination and embedding.
Frequently asked questions
what is json server
It is a tool that turns a JSON file into a full REST API with no coding. You create a db.json or db.json5 file whose top-level keys become your resources, then start the server, and it serves GET, POST, PUT, PATCH and DELETE routes for array resources, along with conditions, sorting, pagination, relation embedding and static file serving from a public directory. The package is MIT licensed.
how to use json server
Write a db.json in the directory you want to serve, then run npx json-server db.json, which starts the server at http://localhost:3000 and prints a startup line naming the port. Query it with curl, for example curl http://localhost:3000/posts/1, which returns the single document as JSON. Run json-server --help for the full list of options.
how to install json-server
The install is npm install json-server. Two things are worth checking before you start. The manifest requires node >=22.12.0, and the package is published from a version field reading 1.0.0-beta.15, while the README's own callout says the v1 documentation is beta with expected breaking changes and points to v0.17.4 as the stable line.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/typicode-json-server)Star history chart for your README
[](https://hysenlabs.com/projects/typicode-json-server)Was this useful?