How to Use JSON Test Data in React and Next.js Projects

June 16, 2026

Building a React or Next.js app without a real backend yet? Or writing component tests that need realistic data? This guide covers every pattern for using JSON test data in React and Next.js — from simple local imports to full API mocking with MSW.


Pattern 1: Local JSON Import (Simplest)

The most straightforward approach — generate your data with Dummy JSON Generator, save the file, and import it directly.

// src/data/users.json  ← your generated file goes here
// Then in your component:

import users from '@/data/users.json';

export default function UserList() {
    return (
        <ul>
            {users.map(user => (
                <li key={user.id}>
                    <img src={user.avatar} alt={user.fullName} />
                    <span>{user.fullName}</span>
                    <span>{user.email}</span>
                </li>
            ))}
        </ul>
    );
}

This works for static prototyping and Storybook stories but doesn't simulate real network behavior (loading states, errors, latency).


Pattern 2: Next.js API Route as Mock Endpoint

Create a Next.js API route that returns your JSON file. This simulates a real API call, including network latency if you want it.

// app/api/users/route.ts  (Next.js App Router)
import { NextResponse } from 'next/server';
import users from '@/data/users.json';

export async function GET() {
    // Optional: simulate network latency
    await new Promise(r => setTimeout(r, 200));
    return NextResponse.json(users);
}
// pages/api/users.ts  (Next.js Pages Router)
import type { NextApiRequest, NextApiResponse } from 'next';
import users from '@/data/users.json';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
    res.status(200).json(users);
}

Your components now fetch from /api/users exactly like they would in production — the only difference is the data comes from your local JSON file.


Pattern 3: MSW — Mock Service Worker

MSW intercepts fetch and axios calls at the network level — in both the browser and Node.js (for Jest/Vitest). It's the most powerful approach for development and testing.

npm install msw --save-dev
npx msw init public/ --save
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';
import users from '@/data/users.json';
import products from '@/data/products.json';

export const handlers = [
    http.get('/api/users', () => {
        return HttpResponse.json(users);
    }),

    http.get('/api/users/:id', ({ params }) => {
        const user = users.find(u => u.id === params.id);
        if (!user) return new HttpResponse(null, { status: 404 });
        return HttpResponse.json(user);
    }),

    http.get('/api/products', () => {
        return HttpResponse.json(products);
    }),

    // Simulate a POST that returns the created resource
    http.post('/api/users', async ({ request }) => {
        const body = await request.json();
        return HttpResponse.json({ id: crypto.randomUUID(), ...body }, { status: 201 });
    }),
];
// src/mocks/browser.ts
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';

export const worker = setupWorker(...handlers);
// src/main.tsx or app/layout.tsx
if ("production" === 'development') {
    const { worker } = await import('./mocks/browser');
    await worker.start({ onUnhandledRequest: 'bypass' });
}

Pattern 4: Vitest / Jest Component Tests with Fake Data

// src/mocks/server.ts  (Node.js MSW server for tests)
import { setupServer } from 'msw/node';
import { handlers } from './handlers';

export const server = setupServer(...handlers);
// vitest.setup.ts
import { server } from './src/mocks/server';
import { beforeAll, afterAll, afterEach } from 'vitest';

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
// UserList.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import UserList from './UserList';

describe('UserList', () => {
    it('renders users from the API', async () => {
        render(<UserList />);

        // Shows loading state first
        expect(screen.getByText('Loading...')).toBeInTheDocument();

        // Then renders the fake data from our MSW handler
        await waitFor(() => {
            expect(screen.getAllByRole('listitem').length).toBeGreaterThan(0);
        });
    });

    it('renders user emails', async () => {
        render(<UserList />);
        await waitFor(() => {
            expect(screen.getByText('ayesha.rahman@example.com')).toBeInTheDocument();
        });
    });
});

Pattern 5: Storybook Stories with Fake Data

// UserCard.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import UserCard from './UserCard';
import users from '@/data/users.json';

const meta: Meta<typeof UserCard> = {
    component: UserCard,
};
export default meta;

type Story = StoryObj<typeof UserCard>;

export const Default: Story = {
    args: { user: users[0] },
};

export const Inactive: Story = {
    args: { user: users.find(u => u.status === 'inactive') },
};

export const LongName: Story = {
    args: {
        user: { ...users[0], fullName: 'Bartholomew Christophersen-Wellington' }
    },
};

Recommended File Structure

src/
├── data/                    ← generated JSON files live here
│   ├── users.json
│   ├── products.json
│   └── orders.json
├── mocks/
│   ├── handlers.ts          ← MSW route handlers
│   ├── browser.ts           ← browser worker setup
│   └── server.ts            ← Node.js server for tests
└── components/
    └── UserList/
        ├── UserList.tsx
        ├── UserList.test.tsx
        └── UserList.stories.tsx

Which Pattern to Use?

PatternBest ForSimulates Network?
Local JSON importStorybook, static prototypesNo
Next.js API routeFull-stack Next.js appsYes
MSW (browser)Frontend dev without backendYes
MSW (Node.js)Jest/Vitest component testsYes

For most React/Next.js projects, the recommended setup is: Local JSON files (generated with Dummy JSON Generator) + MSW for both development and testing. It's the most realistic simulation of production behavior with the least boilerplate.