Mock API requests in Storybook with Mock Service Worker.
npm i msw-storybook-addon -DMake sure you have
msw@2.xinstalled as a peer dependency.
Next, use the MSW CLI to generate a worker script at the given path:
npx msw init ./public --saveReplace
./publicwith the path to your static directory of Storybook.
The loader API for CSF 3.0 is deprecated. Please consider using the CSF Next API instead.
// .storybook/main.ts
export default {
addons: ['msw-storybook-addon'],
}// .storybook/preview.ts
import { mswLoader } from 'msw-storybook-addon/csf3'
export default {
loaders: [mswLoader()],
parameters: {
msw: [...initialHandlers]
}
}Include the addon's types in your tsconfig.json for a type safe parameters.msw experience in your setup and stories:
{
"include": [".storybook/preview.ts", "..."],
"compilerOptions": {
"types": ["msw-storybook-addon/csf3"]
}
}If you are using the CSF Next syntax (also known as CSF Factories), it's enough to import and call the addon function in preview.ts:
// .storybook/preview.ts
import addonMsw from 'msw-storybook-addon'
export default definePreview({
addons: [addonMsw()],
})
parameters.mswis not supported in CSF Next. It is preserved only for CSF 3.0 to make migration easier — use thebeforeEachhook instead.
Include the addon's types in your tsconfig.json for a type-safe experience in your setup and stories:
{
"include": [".storybook/preview.ts", "..."],
"compilerOptions": {
"types": ["msw-storybook-addon/types"]
}
}By default, the addon creates and starts the worker for you: it starts quietly and ignores common asset and Storybook-internal requests. To customize that behavior (e.g. worker.start() options or initial handlers), provide a setup function that creates the worker, starts it, and returns it.
In CSF 3.0, pass it to mswLoader:
// .storybook/preview.ts
import { setupWorker } from 'msw/browser'
import { mswLoader } from 'msw-storybook-addon/csf3'
export default {
loaders: [
mswLoader(async () => {
const worker = setupWorker()
await worker.start({ onUnhandledRequest: 'bypass' })
return worker
})
]
}In CSF Next, pass it to addonMsw:
// .storybook/preview.ts
import { setupWorker } from 'msw/browser'
import addonMsw from 'msw-storybook-addon'
export default definePreview({
addons: [
addonMsw(async () => {
const worker = setupWorker()
await worker.start({ onUnhandledRequest: 'bypass' })
return worker
})
],
})Handlers passed to
setupWorker()act as initial handlers and survive the automatic handler reset between stories.
If you have correctly installed and configured this addon, it will extend your story context with the msw property. Use that reference to control API mocking in your stories, e.g. by adding request handler overrides via msw.use().
Provide request handlers in preview.ts to define the network behaviors that affect all your stories.
// .storybook/preview.ts
import { http, HttpResponse } from 'msw'
export default {
beforeEach({ msw }) {
msw.use(
http.get('https://api.acme.com/user', () => {
return HttpResponse.json({ name: 'John Maverick' })
}),
)
},
}To describe network behaviors on a story basis, add them in the beforeEach hook of the respective story.
export const UserProfileNetworkError: Story = {
beforeEach({ msw }) {
msw.use(
http.get('https://api.acme.com/user', () => {
return HttpResponse.error()
}),
)
},
}