I want a skeleton while data loads, a friendly error page, and a 404 for missing records. Where do these special files go and why does error.tsx need 'use client'?
#nextjs#app-router#error-handling
DEV3 Developer Forum
Every post is reviewed first. Usually reviewed within 24 hours.
I want a skeleton while data loads, a friendly error page, and a 404 for missing records. Where do these special files go and why does error.tsx need 'use client'?
#nextjs#app-router#error-handling
Special files placed in a route segment wrap the page in React boundaries automatically.
A fallback shown through <Suspense> while the segment's async content loads.
// app/dashboard/loading.tsx
export default function Loading() {
return <div className="animate-pulse h-40 rounded bg-gray-200" />;
}
For finer control wrap only the slow part in your own <Suspense fallback={...}> so the rest of the page streams immediately.
An error boundary for the segment and its children. It must be a client component because error boundaries are a client-side React feature.
// app/dashboard/error.tsx
"use client";
export default function Error({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
return (
<div>
<p>Something went wrong.</p>
<button onClick={() => reset()}>Try again</button>
</div>
);
}
In production the message of server errors is hidden; only a digest is shown, so match it against your server logs. global-error.tsx handles errors in the root layout and must render its own <html> and <body>.
Rendered when you call notFound() or no route matches (root level).
import { notFound } from "next/navigation";
const post = await getPost(slug);
if (!post) notFound();
error.tsx does not catch errors thrown in the same segment's layout; place it one level higher.redirect() and notFound() work by throwing internally. Do not wrap them in a try/catch or the redirect is swallowed.