Nr 08 Error Handling
title: "Next.js vs Remix — Error Handling Patterns Compared" description: "Compare error handling in Next.js and Remix including error boundaries, loader errors, form validation errors, and unhandled exceptions." weight: 18 date: 2026-06-28 lastmod: 2026-06-28 tags: [frameworks, react]
Error handling patterns differ between Next.js and Remix. Next.js uses error boundaries and not-found pages. Remix uses ErrorBoundary components and thrown responses.
What You'll Learn
You will understand error handling in both frameworks including expected errors, unexpected errors, form errors, and 404 handling.
Why It Matters
Good error handling improves user experience, aids debugging, and prevents application crashes. Each framework provides different tools for managing errors.
Real-World Use
DodaTech's Remix admin panel renders a custom ErrorBoundary per route section, so a crash in user settings does not affect the user list.
flowchart TD
subgraph Next[Next.js Error Handling]
A1[error.js] --> B1[Client ErrorBoundary]
A2[not-found.js] --> B2[404 Page]
A3[try/catch] --> B3[Server errors]
end
subgraph Remix[Remix Error Handling]
C1[ErrorBoundary] --> D1[Route-level errors]
C2[throw Response] --> D2[HTTP errors]
C3[useActionData] --> D3[Form errors]
end
style Next fill:#121212,color:#fff
style Remix fill:#1a1a2e,color:#fff
Next.js Error Boundaries
Next.js uses error.js files to catch errors in route segments.
'use client';
// app/dashboard/error.js
export default function DashboardError({ error, reset }) {
return (
<div style={{ padding: '24px', textAlign: 'center' }}>
<h2>Dashboard Error</h2>
<p style={{ color: '#666' }}>{error.message}</p>
<button onClick={reset} style={{ padding: '8px 16px', marginTop: '16px' }}>
Try Again
</button>
</div>
);
}
Expected output: If any component in the dashboard route throws an error, the error boundary catches it and displays a friendly message with a retry button.
Next.js Not Found Pages
not-found.js files handle 404 errors for route segments.
// app/not-found.js — Global 404
export default function NotFound() {
return (
<div style={{ textAlign: 'center', padding: '48px' }}>
<h1>404 — Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<a href="/">Go Home</a>
</div>
);
}
// Trigger from a Server Component
export default async function ProductPage({ params }) {
const product = await db.products.findById(params.id);
if (!product) {
notFound();
}
return <ProductDetail product={product} />;
}
Expected output: Calling notFound() triggers the closest not-found.js file. The 404 page displays with a link to the home page.
Remix ErrorBoundary
Remix routes export an ErrorBoundary component for catching errors.
// app/routes/users.$id.jsx
import { useRouteError, isRouteErrorResponse } from '@remix-run/react';
export function ErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
return (
<div>
<h1>{error.status} — {error.statusText}</h1>
<p>{error.data}</p>
</div>
);
}
return (
<div>
<h1>Unexpected Error</h1>
<p>{error.message}</p>
</div>
);
}
Expected output: The ErrorBoundary handles both HTTP errors (404, 500) and unexpected errors. HTTP errors show the status code. Unexpected errors show the error message.
Throwing Responses in Remix Loaders
Remix loaders throw Response objects for HTTP error handling.
export async function loader({ params }) {
const user = await db.users.findById(params.id);
if (!user) {
throw new Response(null, {
status: 404,
statusText: 'User Not Found',
});
}
if (!user.isActive) {
throw new Response('This account has been deactivated', {
status: 403,
});
}
return { user };
}
Expected output: If the user is not found, the 404 ErrorBoundary renders. If the user is deactivated, a 403 error displays with a custom message.
Form Validation Errors
Next.js Server Actions return validation errors as objects from the action function.
Remix actions return validation errors through useActionData.
Common Mistakes
Not creating route-level error boundaries: A single global error boundary catches everything. Route-level boundaries isolate errors so one section does not crash the entire page.
Throwing strings instead of Error objects in Next.js: Always throw Error objects. Strings do not provide stack traces or error boundaries handle them differently.
Not distinguishing between expected and unexpected errors: Expected errors (validation, not found) should return data. Unexpected errors (database down, network failure) should throw.
Forgetting to reset error state in Next.js: The reset function in error.js attempts to re-render the segment. Without it, the error persists until page reload.
Not handling errors in Server Actions: Always wrap database operations in try/catch and return structured error responses rather than throwing.
Practice Questions
- How does Next.js handle 404 errors?
Through not-found.js files at the route segment level. Call notFound() from Server Components or getServerSideProps.
- How does Remix handle HTTP errors in loaders?
Throw a Response object with the desired status code and message. The ErrorBoundary catches it.
- What is the purpose of the reset function in Next.js error.js?
It attempts to re-render the route segment. If the error was transient, the page may render successfully.
- How do you access the error in Remix ErrorBoundary?
Using useRouteError hook. Check if it is a route error response with isRouteErrorResponse().
- What happens if an unhandled error occurs in a Remix loader?
The ErrorBoundary for that route catches it. If no ErrorBoundary exists, the root ErrorBoundary handles it.
Challenge
Build a user profile page that handles three error scenarios: user not found (404), user deactivated (403), and database connection failure (500). Implement in both frameworks with appropriate error boundaries.
Frequently Asked Questions
Mini Project
Build a multi-section dashboard where each section (users, products, analytics) has its own error boundary. One section crashing should not affect the others. Each should have a custom error UI with retry functionality.
What's Next
Compare Middleware capabilities in Next.js and Remix.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro