Next.js Error Handling
Errors happen in every application. A database call fails, an API times out, a user visits a page that does not exist. Next.js gives you dedicated files to handle each type of error so that one broken part of your app does not break the entire experience.
The error.js File
Create a file named error.js inside any route folder. When an error occurs inside a page in that folder, Next.js renders this file instead of crashing the whole page. The rest of your app keeps working normally.
'use client'; // error.js must be a Client Component
export default function Error({ error, reset }) {
return (
<div>
<h2>Something went wrong</h2>
<p>{error.message}</p>
<button onClick={reset}>Try again</button>
</div>
);
}
The error prop contains error details. The reset function attempts to re-render the page. Clicking "Try again" re-runs the component that failed.
Diagram: How error.js Catches Errors
NORMAL FLOW:
Layout → Page renders → User sees page
ERROR FLOW (without error.js):
Layout → Page throws error → Entire app crashes
ERROR FLOW (with error.js):
Layout → Page throws error → error.js renders instead
↑ Layout stays intact, user sees error UI not a crash
Error Boundary Coverage
An error.js file catches errors from its own page and any child components. It does not catch errors from the layout in the same folder. To catch layout errors, place an error.js one level up.
app/
error.js ← Catches errors from the root layout's children
layout.js
page.js
dashboard/
error.js ← Catches errors from dashboard pages only
layout.js
page.js
analytics/
page.js ← If this throws, dashboard/error.js catches it
The not-found.js File
When a user visits a URL that does not match any page, Next.js shows a 404 page. Create not-found.js in the app/ folder to customize this page.
// app/not-found.js
export default function NotFound() {
return (
<main>
<h1>404 – Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<a href="/">Go back home</a>
</main>
);
}
Triggering the Not Found Page Manually
Inside a page or server component, call notFound() from next/navigation to trigger the 404 page when data is missing.
import { notFound } from 'next/navigation';
export default async function BlogPost({ params }) {
const post = await fetchPost(params.slug);
if (!post) {
notFound(); // Renders not-found.js for this route segment
}
return <article>{post.title}</article>;
}
The global-error.js File
For errors that happen inside the root layout itself — which error.js cannot catch — create a global-error.js file in the app/ folder. This file replaces the entire page, including the layout, so it must include its own <html> and <body> tags.
// app/global-error.js
'use client';
export default function GlobalError({ error, reset }) {
return (
<html>
<body>
<h1>A critical error occurred</h1>
<p>{error.message}</p>
<button onClick={reset}>Try again</button>
</body>
</html>
);
}
Handling Errors in Server Actions
When a server action fails, wrap the logic in a try-catch block and return an error state to the component.
// app/actions.js
'use server';
export async function createUser(formData) {
try {
const name = formData.get('name');
await db.users.create({ name });
return { success: true };
} catch (error) {
return { success: false, message: 'Failed to create user' };
}
}
Diagram: Which File Handles Which Error
SCENARIO FILE THAT HANDLES IT ───────────────────────────────────────────────────── Page throws an error error.js (same folder) URL does not match any route not-found.js notFound() called in code not-found.js (that segment) Root layout crashes global-error.js API route fails Handled inside route.js itself
Logging Errors
The error prop in error.js gives you the error object. Send it to an error tracking service like Sentry to monitor and fix issues in production.
'use client';
import { useEffect } from 'react';
export default function Error({ error, reset }) {
useEffect(() => {
// Send to your error monitoring service
console.error('Page error:', error);
// logErrorToService(error);
}, [error]);
return (
<div>
<h2>Something went wrong</h2>
<button onClick={reset}>Try again</button>
</div>
);
}
Key Takeaway
Use error.js to catch runtime errors within a route segment and show a helpful message instead of crashing. Use not-found.js for missing pages and call notFound() when data is absent. Use global-error.js as a last resort for root layout failures. Always mark error files with 'use client' since they need the reset function to work.
