Fullstack CourseLearn by building
Back to week 3

Topic

Handle loading and errors

Definition

App Router special files such as loading.tsx and error.tsx define route-segment loading UI and recoverable error boundaries.

In simpler words

Show honest waiting UI and a nearby recovery path when a route cannot render.

Route boundaries complement, rather than replace, request states inside interactive client components.

After this you can

  • Add route-level loading and error fallbacks
  • Explain why error.tsx is client-side
  • Distinguish route failures from mutation errors

Put fallbacks near the route

loading.tsx supplies immediate feedback while a route segment streams. It should resemble the eventual content enough that the interface does not jump or mislead users.

error.tsx is a Client Component boundary. It receives an error and reset callback so users can retry a transient route-rendering failure without manually refreshing the browser.

A recoverable route error boundary

'use client';
export default function ErrorPage({ reset }: { reset: () => void }) {
  return <section><p role="alert">Could not load this page.</p><button onClick={reset}>Try again</button></section>;
}

The reset callback asks Next to retry the route segment.

Mistake: hiding a failure with null

// Wrong — user sees an unexplained blank screen
if (error) return null;

// Right
if (error) return <p role="alert">Could not load tickets. Try again.</p>;

Every error path needs visible context and a useful next step.

Handle request errors where users act

Definition

A route boundary catches rendering failures, while a Query or mutation error belongs near the list or form that initiated the request.

In simpler words

A failed submit should preserve the user’s draft and explain how to retry.

Use accessible status and alert semantics for asynchronous feedback.

Do not expose raw backend internals in a user-facing message; log diagnostic context separately.

Live playground

Error handling playground

Cause a route and a mutation failure, then compare their recovery UI.

Show skeleton while the segment streams.

Keep in mind

  • Use loading.tsx for segment-level waiting UI.
  • Make error.tsx a Client Component that offers reset.
  • Keep failed form drafts visible for correction and retry.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥80% (enforced by the API) to save progress.

Checking your session…

15 questions · concept 5 · syntax 3 · practical 4 · logic 3

1. error.tsx role?
Concept
2. global-error.tsx?
Syntax
3. not-found.tsx?
Practical
4. throw notFound()?
Logic
5. Client error boundaries vs error.tsx?
Concept
6. Recover action?
Practical
7. Logging errors?
Syntax
8. Distinguishing 404 vs 500 in UI?
Logic
9. Async error in Server Component?
Concept
10. Which practice is best?
Practical
11. What does reset() do here?
Conceptintermediate
'use client';
export default function Error({ error, reset }) {
  return <button onClick={() => reset()}>Retry</button>;
}
12. What does calling notFound() do?
Syntaxintermediate
import { notFound } from 'next/navigation';
if (!ticket) notFound();
13. What is the problem with this error UI in production?
Practicaladvanced
export default function Error({ error }) {
  return <pre>{error.stack}</pre>;
}
14. When should each of these render?
Logicadvanced
// app/error.tsx exists, app/not-found.tsx exists
15. Where does this thrown error go?
Conceptintermediate
export default async function Page() {
  const data = await load(); // throws
}

Checking your session…