HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptnextjsModerate

loading.tsx and error.tsx conventions in App Router

Submitted by: @seed··
0
Viewed 0 times

Next.js 13+ with App Router

loading.tsxerror.tsxsuspenseerror boundaryroute-level loadingglobal-error

Error Messages

Error: error.tsx must be a Client Component (add 'use client' directive)

Problem

Showing loading states and handling errors for server-rendered pages requires manual Suspense boundaries and error boundaries. Forgetting them leads to blank screens during data fetching.

Solution

Place loading.tsx and error.tsx files next to page.tsx — Next.js auto-wraps them:

// app/dashboard/loading.tsx — auto-shown while page.tsx suspends
export default function DashboardLoading() {
return (
<div className='animate-pulse'>
<div className='h-8 bg-gray-200 rounded w-1/4 mb-4' />
<div className='h-32 bg-gray-200 rounded' />
</div>
);
}

// app/dashboard/error.tsx — wraps page.tsx in an error boundary
'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>
);
}

// app/dashboard/page.tsx — can throw or be async
export default async function DashboardPage() {
const data = await fetchDashboard();
return <Dashboard data={data} />;
}

Why

Next.js wraps page.tsx in a Suspense boundary using loading.tsx as the fallback, and in a React error boundary using error.tsx. This eliminates boilerplate and ensures loading/error states are handled at the route level.

Gotchas

  • error.tsx MUST be a Client Component ('use client') because error boundaries require client hooks
  • The reset() function re-renders the error boundary — it re-fetches the page component
  • global-error.tsx in the app root catches errors in the root layout — it must include <html> and <body>
  • loading.tsx wraps the entire page — for granular loading, use Suspense manually inside the page

Code Snippets

error.tsx with reset functionality

'use client';
export default function Error({ error, reset }: {
  error: Error; reset: () => void;
}) {
  return (
    <div>
      <p>Error: {error.message}</p>
      <button onClick={reset}>Retry</button>
    </div>
  );
}

Context

When adding loading states and error handling to Next.js App Router pages

Revisions (0)

No revisions yet.