background-linesCreated with Sketch.

Build a production-ready frontend, even if your API doesn't exist.

Mirage JS is an API mocking library that lets you build, test and share a complete working JavaScript application without having to rely on any backend services.

Sign up for updates and to find out when the project's ready:

Have you ever worked on a React or Vue app that needed to talk to a backend API before it was ready?

If so, how’d you handle it?

Maybe you created some mock data directly in your app just to keep you moving:

export function App() {
  let [users, setUsers] = useState([])

  useEffect(() => {
    // API not ready
    // fetch('/api/users')
    //   .then(response => response.json())
    //   .then(json => setUsers(;

    // Use dummy data for now
      { id: "1", name: "Luke" },
      { id: "2", name: "Leah" },
      { id: "3", name: "Anakin" },
  }, [])

  return (
      { => (
        <li key={}>{}</li>

Seems harmless enough.

Weeks later, the server’s ready and you wire up your app — but nothing works like it did during development.

Some screens flash with missing data, others are broken entirely, and worst of all, you have no idea how much of your code needs to be rewritten.

What went wrong?

You ignored the network for too long.

Networking code isn't the kind of thing you can just tack on to the end of a sprint.

Think about everything that comes along with making network requests: loading and error states, fetching partial data, caching... not to mention the fact that asynchronous APIs like network requests add tons of new states to each one of your app's existing user flows.

If you don't grapple with this crucial part of your application up front, you'll have to rewrite a ton of code when it comes time to deploy your app.

You're not doing yourself any favors by writing code that pretends the network doesn't exist. You're just poking holes in reality. And code that ignores reality isn't ready for production.

What if you could have the best of both worlds?

What if you could still mock data in your frontend app, but be sure that your application code could only access that data in the same way it accesses real production data?

That way, you'd be writing code that was ready for the network from day one.

Mirage JS let's you do exactly that.

Here's how it works:

import React from "react"
import ReactDOM from "react-dom"
import App from "./app"
import { Server } from "miragejs"

if (process.env.NODE_ENV === "development") {
  new Server({
    routes() {
      this.get("/users", () => [
        { id: "1", name: "Luke" },
        { id: "2", name: "Leah" },
        { id: "3", name: "Anakin" },

ReactDOM.render(<App />, document.getElementById("root"))

You start by defining your API endpoints in Mirage. When you boot up your frontend, Mirage kicks in automatically. There's no separate server process for you to manage in yet-another terminal tab.

In development, your components can fetch data from Mirage's API endpoints, just as if they were talking to a real server. Your app won't contain a single line of code that reveals you're using Mirage under-the-hood, because it won't even know it's talking to Mirage instead of a real API.

When you're ready to deploy, simply build your app without Mirage, and point it at your production API server.

With Mirage, you'll never write throwaway network code again.

Mirage is a server that runs in the browser.

And it comes with all the power you'd expect from a real server.

You can tweak things like latency, error codes, and HTTP headers. There's an in-memory database that lets you build dynamic features involving persistent data. And you can even use all this functionality within your tests.

Here's a complete Todo application built with Mirage and React:


All done!

    This app is running in the browser, but Mirage is intercepting all the React app's network requests.

    Check out the code for the React app. You'll see it's doing things like making fetch requests and dealing with loading states.

    And here's the code for the Mirage server. It has route handlers defined for each API endpoint the React app needs, and they use the in-memory database to store and modify the server-side representation of the todos over time.

    The data is not actually being persisted to a real server. But the React app is deployable, and ready to talk to a real API that fulfills the same contract that Mirage is providing.

    Once you see how much confidence you can have building fully dynamic features entirely in your frontend codebase, you'll wonder how you ever did it any other way.

    Interested in Mirage and the frontend-first workflow?

    Sign up for updates and to find out when the project's ready: