Mocking backend with json-server and concurrently


When you’re building fullstack apps, switching constantly between frontend and backend can slow you down. Sometimes you’re waiting on the API to be ready. Sometimes you just want to test your UI against data - now.

This is where json-server and concurrently come in.

With just a few lines of config, you can mock a full REST API, seed it with custom data, and run it alongside your frontend - no waiting for real backend endpoints.


Why it’s worth using

As a frontend developer, this lets you:

  • Develop UI before backend is ready
  • Simulate different API states (empty, partial, paginated)
  • Work offline or without a dev server
  • Reduce friction when testing UI logic

As a fullstack dev, you gain:

  • Flexibility: Build BO or FO first — whichever you feel like
  • Easier onboarding for others (or your future self)
  • Clean separation between layers while still moving fast

Step 1 – Install the tools

npm install -D json-server concurrently

Step 2 – Create a mock database

Create a file in the root of your project:

{
  "users": [
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob" }
  ],
  "flashcards": [
    { "id": 1, "deck": "Spanish", "front": "hola", "back": "hello" },
    { "id": 2, "deck": "Spanish", "front": "adiós", "back": "goodbye" }
  ]
}

This gives you REST endpoints like:

  • GET /users

  • GET /flashcards

  • POST /flashcards

  • PUT /flashcards/1

  • DELETE /users/2

Step 3 – Add scripts to package.json

{
  "scripts": {
    "dev": "concurrently \"npm:dev:fe\" \"npm:dev:api\"",
    "dev:fe": "vite",
    "dev:api": "json-server --watch db.json --port 5000"
  }
}

Now just run:

npm run dev

And both the frontend and mock backend will start at once

Step 4 - Use a .env file

To make your mock API path easily swappable later, add this to .env:

VITE_API_URL=http://localhost:5000

Then in your frontend, fetch data like this (example in Vue):

const res = await fetch(`${import.meta.env.VITE_API_URL}/flashcards`);
const data = await res.json();

When you switch to a real backend, just update the .env file — no code changes needed.


Bonus - Custom routes or middlewares

Want to customize behavior? You can:

  • Add a routes.json file to remap endpoints
  • Use json-server with a JavaScript config to include your own middleware (e.g. for auth, artificial delays, logging, etc.)

Example routes.json:

{
  "/api/users": "/users",
  "/api/cards": "/flashcards"
}

Then run:

json-server --watch db.json --routes routes.json

You can also replace —watch with a JS config using json-server as a module if you want advanced control.

Summary

Using json-server + concurrently helps you:

  • Move faster

  • Mock data easily

  • Focus on building, not waiting

Perfect for:

  • Quick prototypes

  • Isolated frontend development

  • API integration testing

Once you try it, it’s hard to imagine going back.

Bartłomiej Nowak

Bartłomiej Nowak

Programmer

Programmer focused on performance, simplicity, and good architecture. I enjoy working with modern JavaScript, TypeScript, and backend logic — building tools that scale and make sense.

Recent Posts