JSON Server enables frontend developers to quickly spin up a fake REST API to validate how an app’s interface reacts when receiving data from the backend. This is especially useful when the required backend routes have not been finished yet.
At a high level, there’s not much to it: all you need to do is create a JSON file that defines endpoints and sample data — no further configuration required. In fact, you can bootstrap a fake REST API in under five minutes.
In this tutorial, we’ll demonstrate:
GET, POST, and PUT requestsLet’s dig in!
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
Before we can send any request, we need to install JSON Server. Preferably, we’d use npm to install the json-server package globally.
npm install -g json-server
Now that JSON Server has been globally installed, we can create our first server configuration.
The next step is to create our first db.json file, which holds the JSON configuration for the fake REST API. Below is a sample configuration, which includes three endpoints: authors, books, and library.
{
"authors": [
{ "id": 1, "name": "Michiel Mulders", "genre": "fiction" }
],
"books": [
{ "id": 1, "title": "some title", "authorId": 1 }
],
"library": { "name": "City library" }
}
Note how we define endpoints: every endpoint with a plural name contains an array of objects, and each object represents a database record for that endpoint. For example, the authors endpoint will return one author object with id: 1 and name equal to Michiel Mulders.
For plural endpoints, JSON Server generates the following routes:
GET /authors returns all authorsGET /authors/1 returns author with ID 1POST /authors creates a new author in the databasePUT /authors/1 updates the entire author object for ID 1PATCH /authors/1 updates specific fields for the author object with ID 1DELETE /authors/1 deletes a specific author objectThe JSON configuration shows a singular endpoint library. When you define an endpoint in its singular form, it can only return one object. It’s not possible to define an array.
As for the generated routes for a singular endpoint, GET/POST/PUT/PATCH /library is basic set of operations available for the object, but it is not able to delete the object.
Now we understand the possible routes JSON Server generates. Let’s start our first server!
To start the server and serve the above endpoints, we’ll use the json-server command in the command line. We’ll tell the json-server command to watch our db.json configuration file.
json-server --watch db.json
You can verify that your server is running by sending a GET request to http://localhost:3000/authors/1. If it returns a result, you are ready to explore other endpoints.
POST requestWe can send a POST request via Postman or curl. Don’t forget to pass the correct headers for the request. Since we’re dealing with a JSON API, we need to send the Content-Type: application/json header.
A POST request can simply be sent via a request body. The body below will create a new author object in our database. Don’t forget to send the request to the correct URL: http://localhost:3000/authors.
{
"name": "Gregory Salis",
"genre": "nonfiction"
}
As you can see, the request body doesn’t have to pass an ID. JSON Server will automatically create a new ID for your author object.
PUT requestSending a PUT request is very similar to sending a POST request. First we must specify the ID of the object that needs to be updated. Let’s update the original author object with ID 1 using the URL http://localhost:3000/authors/1.
The PUT request has to modify the genre from fiction to nonfiction. Therefore, the request body will look like this:
{
"name": "Michiel Mulders",
"genre": "nonfiction"
}
Besides sending simple GET, POST, and PUT requests, JSON Server allows for more advanced requests such as filtering, sorting, and searching.
To enrich its functionality, JSON Server comes with searching, sorting, and filtering options.
Data can be sorted through the _sort option. Let’s say we want to sort authors by genre. The sort request will look like this:
http://localhost:3000/authors?_sort=genre
However, the order of the sorting result needs to be switched from asc to desc. The _order option allows us to change the sorting from ascending to descending.
http://localhost:3000/authors?_sort=genre&_order=desc
We can achieve data filtering by defining the field and required value we want to filter for. The example link below would retrieve all nonfiction authors. The request defines the genre field and the required value nonfiction.
http://localhost:3000/authors?genre=nonfiction
Also, JSON Server allows us to combine filters. Now the request should retrieve all nonfiction books by the author Michiel Mulders. The below request defines two fields which are chained by the ampersand (&) character.
http://localhost:3000/authors?genre=nonfiction&name=Michiel%20Mulders
Note: The space between Michiel and Mulders is encoded by %20. This is a common practice for encoding URLs. Lastly, json-server provides several searching possibilities.
Last but not least, searching can be performed in various ways. The full text search option helps with finding a specific value. This approach is easiest when looking for values. Here, the request should find all authors that include “Michiel” in their name.
http://localhost:3000/authors?q=michiel
Moreover, JSON Server helps with finding values for specific fields. For example, the request should return all matching records that include “Michiel” in the genre field. When investigating the db.json file, this request should return an empty response because “Michiel” does not appear in the genre field.
We can filter by appending the _like operator to the field we want to search for. Now, the request includes a genre_like option.
http://localhost:3000/authors?genre_like=michiel
Also, the _like operator supports regular expression queries. The following query should retrieve all genres that start with the non keyword. Notice the asterisk symbol appended to the genre_like option — that’s part of the regex.
http://localhost:3000/authors?genre_like=non*
More operators, such as _gte, _lte, and _ne, can be found in the JSON Server documentation.
A fake JSON server that doesn’t come with the ability to define relationships between endpoints would be quite useless. Most data requires the ability to define data relationships. Let’s discuss how json-server allows for the definition of relationships between data points.
First, remember the db.json configuration we started with:
{
"authors": [
{ "id": 1, "name": "Michiel Mulders", "genre": "fiction" }
],
"books": [
{ "id": 1, "title": "some title", "authorId": 1 }
],
"library": { "name": "City library" }
}
Now notice the authorId field for the books endpoint. By using the singular form of another data entity in our database, we can link it by appending the id keyword. Here we’ve linked a book with the title “some title” to the author with ID 1.
Furthermore, this allows us to query for all books written by Michiel Mulders, the author with the ID equal to 1. The query requires the addition of the books keyword to specify the retrieval of all books for this author.
http://localhost:3000/authors/1/books
Again, we further filter for those endpoints, such as the following request.
http://localhost:3000/authors/1/books?title_like=some
But what if we want to include the parent resource (authors)?
Moreover, json-server allows us to include the parent resource through the _embed option. The request will look slightly different now because we are starting from the authors endpoint and asking to embed all books for the author with an ID equal to 1.
http://localhost:3000/authors/1?_embed=books
The result looks like this when sending the above GET request:
{
id: 1,
name: "Michiel Mulders",
genre: "fiction",
books:
[
{
id: 1,
title: "some title",
authorId: 1
}
]
}
To wrap up our tutorial, we’ll review some common best practices to help you get the most out of json-server.
Besides generating routes, json-server ships with many other interesting features that can be useful for you. Let’s explore four of the most interesting features.
Imagine you’ve updated and created many new objects and you don’t want to lose your progress. You can hit s + enter on your keyboard to take a snapshot of the current database state.
The snapshot is saved in the same folder and the name will be appended with a unix timestamp, producing something like this: db-1578083664783.json.
The name “custom routes” is actually quite misleading. json-server allows you to create aliases for existing routes.
Let’s say your frontend relies on an API that is served from the root path starting with /api/v1. Since json-server does not include this prefix, we have to create a custom route. We’ll create a routes.json file to tell json-server which mappings to establish. The below example maps all json-server routes to the required prefix /api/v1.
{
"/api/*": "/$1"
}
Next, we can also create shorter paths for long URLs.
{
"/api/*": "/$1",
"/:resource/:id/show": "/:resource/:id"
}
To tell json-server to use these aliases, pass the --routes option to the start command.
json-server --watch db.json --routes routes.json
By default, json-server serves its API on port 3000. We can change the port with the --port option.
json-server --watch db.json --port 5000
Lastly, json-server allows you to define custom middleware. For example, let’s create a headers.js file that contains a small snippet of code to add an extra custom header to the request.
json-server follows the same pattern that Express.js uses for requests: req, res, and next. Therefore, you can modify the data for a request or add an extra header to the res object, like this:
module.exports = (req, res, next) => {
res.header('X-Hello', 'World')
next()
}
To serve json-server with the above middleware, pass the --middlewares option.
json-server --watch db.json --middlewares headers.js
Before you start running wild with your mock APIs, let’s quickly recap what we learned.
JSON Server focuses on simplicity and speed of use. It allows any frontend developer to spin up a fake REST API in under five minutes.
Furthermore, it’s easy to add relationships between data. Simply adding the id keyword enables you to link any data. json-server allows you to filter, sort, and query for data just like a regular API.
Next time you’re validating frontend components, consider using json-server to quickly bootstrap a JSON REST API. When your project requires special components, json-server allows for customizations through middleware.
To see what else you can do with JSON Server, check out the official documentation.
Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not
server-side
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
// Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>

line-clamp to trim lines of textMaster the CSS line-clamp property. Learn how to truncate text lines, ensure cross-browser compatibility, and avoid hidden UX pitfalls when designing modern web layouts.

Discover seven custom React Hooks that will simplify your web development process and make you a faster, better, more efficient developer.

Promise.all still relevant in 2025?In 2025, async JavaScript looks very different. With tools like Promise.any, Promise.allSettled, and Array.fromAsync, many developers wonder if Promise.all is still worth it. The short answer is yes — but only if you know when and why to use it.

Discover what’s new in The Replay, LogRocket’s newsletter for dev and engineering leaders, in the October 29th issue.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now