Introduction
MSW (Mock Service Worker) changed how frontend teams mock APIs. Instead of stubbing fetch or swapping your HTTP client, MSW installs a service worker (in browsers) or an interceptor (in Node) that sees every request and returns a fake response when a handler matches.
With over 18,000 GitHub stars, MSW is used by Storybook, Netflix, Microsoft, and most React/Vue teams that need realistic API mocks for Storybook, Playwright tests, Vitest/Jest unit tests, and local development.
What MSW Does
You define request handlers (like Express routes). MSW installs a proxy layer: a service worker in browsers, an HTTP interceptor in Node (via @mswjs/interceptors). Matching requests are answered by your handlers; unmatched requests pass through to the real server.
Architecture Overview
Application fetch/axios/XHR
|
[Browser] [Node test runner]
| |
[Service Worker] [Interceptor]
(public/mockServiceWorker.js)
| |
[MSW Runtime] <-- handlers --> [MSW Runtime]
|
Match? -> HttpResponse.json(...)
Miss? -> pass-through to real networkSelf-Hosting & Configuration
// Node: Vitest/Jest setup
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
const server = setupServer(...handlers);
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
// Per-test override
server.use(
http.get("/api/user", () =>
HttpResponse.error() // simulate network failure
)
);
// GraphQL
import { graphql } from "msw";
export const gqlHandlers = [
graphql.query("GetUser", () =>
HttpResponse.json({ data: { user: { id: 1, name: "Alice" } } })
),
];Key Features
- Network-level interception — your code uses real fetch/axios
- Works everywhere — browser, Node, React Native, Deno, Bun
- REST and GraphQL — both have dedicated handler helpers
- Storybook integration — msw-storybook-addon for visual testing
- Type safety — generics for request/response types
- Scenario overrides —
server.use()swaps handlers per test - Pass-through mode — let some requests hit real backends
- DevTools — browser extension shows intercepted requests
Comparison with Similar Tools
| Feature | MSW | nock | miragejs | json-server | Pact |
|---|---|---|---|---|---|
| Layer | Network (SW/Interceptor) | HTTP (Node only) | In-memory store | HTTP server | Contract testing |
| Browser | Yes | No | Yes | Via server | Via broker |
| Node | Yes | Yes | Limited | Yes | Yes |
| REST | Yes | Yes | Yes | Yes | Yes |
| GraphQL | Yes | Manual | Yes | No | Limited |
| Best For | Universal mocks | Node-only tests | Full fake backend | Quick prototype | Contract validation |
FAQ
Q: Why service worker and not just stubbing fetch? A: Service workers intercept every request type (fetch, XHR, img, script). Stubs only cover one API. MSW tests what actually hits the wire.
Q: Can I use MSW in production?
A: No, MSW is for development and tests. Never ship the service worker to prod — guard it behind NODE_ENV !== "production".
Q: MSW vs json-server? A: json-server spins up a real HTTP server. MSW runs inside the same process with zero infra. MSW is better for Storybook, tests, and offline dev.
Q: Does MSW work with Next.js?
A: Yes. Use msw/browser for client components and msw/node for API routes + server components in tests.
Sources
- GitHub: https://github.com/mswjs/msw
- Docs: https://mswjs.io
- Author: Artem Zakharchenko
- License: MIT