Filenames That Build Up the UX
File Conventions — loading, error, not-found
Special filenames create UI boundaries. loading.tsx suspends UI, error.tsx catches errors, and not-found.tsx renders when notFound() is called.
What you'll learn
- Use `loading.tsx` for instant skeletons
- Use `error.tsx` as an error boundary
- Use `not-found.tsx` for 404s
Next.js turns a handful of specially named files into UI boundaries. You write the component; Next.js wires up the Suspense and Error Boundary plumbing.
loading.tsx — Instant Skeleton
A loading.tsx next to a page.tsx automatically wraps the page in <Suspense>. The
fallback is shown until the server component finishes rendering.
// app/dashboard/loading.tsx
export default function Loading() {
return <div className="skeleton">Loading dashboard…</div>;
} You do not import or wire this anywhere — the filename is the wiring.
error.tsx — Segment Error Boundary
An error.tsx becomes the React error boundary for its segment. It must be a Client
Component because it uses hooks like useEffect for logging and reset for retry.
// app/dashboard/error.tsx
'use client';
import { useEffect } from 'react';
export default function DashboardError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<div>
<h2>Something went wrong.</h2>
<button onClick={() => reset()}>Try again</button>
</div>
);
} not-found.tsx — Friendly 404
When a server component calls notFound(), Next.js renders the closest
not-found.tsx instead of the page.
// app/blog/[slug]/not-found.tsx
export default function PostNotFound() {
return <h2>That post does not exist.</h2>;
} // app/blog/[slug]/page.tsx
import { notFound } from 'next/navigation';
export default async function PostPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await fetchPost(slug);
if (!post) notFound();
return <article>{post.title}</article>;
} Catastrophic Failures
If even the root layout crashes, app/global-error.tsx takes over. It must render its
own <html> and <body>. Most apps never need to define one — but knowing it exists
is useful.