Jest Setup with Next.js
Configure Jest with Next.js using the official next/jest preset for zero-config TypeScript and path alias support.
Search across all documentation pages
Configure Jest with Next.js using the official next/jest preset for zero-config TypeScript and path alias support.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Quick-reference recipe card -- copy-paste ready.
# Install dependencies
npm install -D jest @testing-library/react @testing-library/jest-dom @testing-library/user-event jest-environment-jsdom ts-node @types/jest// jest.config.ts
import type { Config } from "jest";
import nextJest from "next/jest";
const createJestConfig = nextJest({
dir: "./", // Path to your Next.js app (loads next.config.js and .env)
});
const config: Config = {
testEnvironment: "jsdom",
setupFilesAfterSetup: ["<rootDir>/jest.setup.ts"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
};
export default createJestConfig(config);// jest.setup.ts
import "@testing-library/jest-dom";// package.json scripts
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
}
}When to reach for this: When you have an existing Jest setup, need Jest-specific plugins, or prefer the mature Jest ecosystem with full Next.js integration via next/jest.
// src/components/counter.tsx
"use client";
import { useState } from "react";
export function Counter({ initial = 0 }: { initial?: number }) {
const [count, setCount] = useState(initial);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
<button onClick={() => setCount((c) => c - 1)}>Decrement</button>
</div>
);
}// src/components/counter.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Counter } from "./counter";
describe("Counter", () => {
it("renders with initial count", () => {
render(<Counter initial={5} />);
expect(screen.getByText("Count: 5")).toBeInTheDocument();
});
it("increments on click", async () => {
const user = userEvent.setup();
render(<Counter />);
await user.click(screen.getByRole("button", { name: "Increment" }));
expect(screen.getByText("Count: 1")).toBeInTheDocument();
});
it("decrements on click", async () => {
const user = userEvent.setup();
render(<Counter initial={3} />);
await user.click(screen.getByRole("button", { name: "Decrement" }));
expect(screen.getByText("Count: 2")).toBeInTheDocument();
});
});What this demonstrates:
next/jest handles TypeScript transforms and CSS module mocking automaticallyuserEvent.setup() for realistic user interaction simulationnext/jest creates a Jest config that integrates with Next.js's SWC compiler for fast transforms (no Babel needed)next/font so they do not break testsdir option tells Next.js where to find next.config.js to load environment variables and module aliasessetupFilesAfterSetup runs after the test framework is installed in the environment -- this is where you load @testing-library/jest-dom matchersmoduleNameMapper replicates tsconfig.json path aliases so @/components/... resolves correctlyTransform config for specific file types:
// jest.config.ts - next/jest handles most transforms, but you can add custom ones
const config: Config = {
transform: {
"\\.svg$": "<rootDir>/test/svg-transform.ts",
},
};Running a subset of tests:
# Run tests matching a pattern
jest --testPathPattern="components"
# Run a single file
jest src/components/counter.test.tsx
# Run tests matching a name
jest -t "increments"Collecting coverage:
// jest.config.ts
const config: Config = {
collectCoverageFrom: [
"src/**/*.{ts,tsx}",
"!src/**/*.d.ts",
"!src/**/index.ts",
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
};// If using ts-node for jest.config.ts, ensure tsconfig allows it
// tsconfig.json
{
"compilerOptions": {
"types": ["jest", "@testing-library/jest-dom"]
}
}
// For ESM projects, you may need:
// jest.config.ts
// export default createJestConfig(config) - next/jest handles ESM interopnext/jest requires Next.js 13.1+ -- Older versions lack the SWC-based Jest integration. Fix: Upgrade Next.js or configure Babel manually.
CSS import errors -- If you see SyntaxError: Unexpected token on .css files, next/jest is not applied correctly. Fix: Ensure createJestConfig wraps your config and dir points to your project root.
ESM packages failing -- Some npm packages ship ESM-only and Jest defaults to CommonJS. Fix: Add them to transformIgnorePatterns:
const config: Config = {
transformIgnorePatterns: [
"node_modules/(?!(swiper|ky|nanoid)/)",
],
};Slow test startup -- Jest has higher startup cost than Vitest due to module resolution. Fix: Use --watch mode during development to cache transforms across runs.
setupFilesAfterSetup vs setupFiles -- setupFiles runs before the test framework loads, setupFilesAfterSetup runs after. Jest-dom matchers must go in setupFilesAfterSetup. Fix: Use setupFilesAfterSetup for @testing-library/jest-dom.
| Alternative | Use When | Don't Use When |
|---|---|---|
| Vitest | You want faster watch mode, native ESM, and Vite-based transforms | You need Jest-specific plugins or have a large existing Jest suite |
@swc/jest | You need SWC transforms without the Next.js preset | You are using Next.js (use next/jest instead) |
| Bun test | You use Bun as your runtime and want built-in testing | You need the Jest ecosystem of matchers and plugins |
next/font.next.config.js for environment variables and module aliases.setupFiles runs before the test framework loads.setupFilesAfterSetup runs after. Jest-dom matchers must go in setupFilesAfterSetup because they extend Jest's expect.This means next/jest is not applied correctly. Ensure createJestConfig wraps your config and the dir option points to your project root.
Add them to transformIgnorePatterns:
transformIgnorePatterns: [
"node_modules/(?!(swiper|ky|nanoid)/)",
],--watch mode during development to cache transforms across runs.It will not work. The SWC-based Jest integration requires Next.js 13.1+. For older versions, configure Babel manually.
jest -t "increments"This runs only test cases whose names match the string "increments".
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},Add both to your tsconfig.json:
{
"compilerOptions": {
"types": ["jest", "@testing-library/jest-dom"]
}
}Jest does not parse tsconfig.json path aliases. You must replicate them in moduleNameMapper or use next/jest which handles some alias resolution via the dir option.
Yes. Add a transform entry in your Jest config:
transform: {
"\\.svg$": "<rootDir>/test/svg-transform.ts",
},Import the Config type from Jest:
import type { Config } from "jest";
const config: Config = { /* ... */ };Reviewed by Chris St. John·Last updated Jul 10, 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥