Skip to content
beginner Phase 2 · App Router, Layouts, and Pages

loading.tsx and error.tsx Files

Show instant feedback and recoverable fallbacks per segment.

40m
0 problems
Topic Progress 0%

Instant Loading UI with loading.tsx

The loading.tsx file (or loading.js) is a special file in the app router that renders immediately when a segment's data fetch is still pending. This provides instant UI feedback to the user, rather than showing a blank screen or spinner while the server data loads. This is one of the most user experience–improving features of the app router, because it eliminates the blank screen or spinner that users traditionally saw while waiting for data.

How it works: When a navigation occurs (via next/link or useRouter()), Next.js starts fetching the data for the new segment. If the fetch hasn't completed by the time the UI would normally render, Next.js renders the loading.tsx file for that segment. This feature is automatic and requires no additional configuration beyond creating the loading.tsx file in the appropriate directory.

Placement and inheritance:

  • app/dashboard/loading.tsx renders while any route under /dashboard is loading.
  • app/dashboard/settings/loading.tsx renders specifically while /dashboard/settings is loading, taking precedence over the parent.
  • If a child has its own loading.tsx, it takes priority; otherwise, the parent's loading.tsx is shown.
  • The root app/loading.tsx renders while any route in the app is loading.

Typical content: A loading UI should be lightweight and appear instantly. Common patterns include:

  • A skeleton version of the page content (using skeleton from CSS or a loading component library such as Chakra UI, Tailwind, or Radix UI).
  • A spinner or progress indicator using CSS animations or component libraries.
  • A simplified version of the page with minimal data, such as a title and brief description.
  • The layout chrome (sidebar, header) from the parent layout, since layouts persist across navigation and provide context to the user during the loading state.
// app/dashboard/loading.tsx
import { Skeleton } from '@chakra-ui/react'
export default function DashboardLoading() {
  return (
    <div className="p-4">
      <Skeleton className="h-6 w-20" />
      <Skeleton className="h-6 w-40" />
      <Skeleton className="h-6 w-full" />
    </div>
  )
}

Inheritance and precedence:

  • Child segment loading.tsx takes precedence over parent. This means if you have app/dashboard/settings/loading.tsx and app/dashboard/loading.tsx, the child version is rendered when navigating to /dashboard/settings.
  • If no child loading.tsx exists, the parent's is shown. This provides a fallback loading UI for the parent segment.
  • Root app/loading.tsx is the fallback for any app-wide loading. This is the outermost loading UI and renders for all routes in the application.

Interview framing: When asked about loading.tsx, a strong answer explains that it provides instant UI feedback during data fetching, rendering immediately while the server fetch is pending. Mentioning that it inherits the parent layout (since layouts persist across navigation) shows you understand the composition model. Discussing the typical content patterns (skeletons, spinners) and the inheritance/precedence hierarchy demonstrates depth. Interviewers also appreciate candidates who can explain why the loading UI should be lightweight and not attempt to fetch additional data.

Why it matters: The loading.tsx feature directly improves core web vitals by reducing the perceived load time. When a user navigates to a new page, they see immediate content rather than a blank screen, which reduces bounce rates and improves engagement. This feature is one of the most user-centric improvements in the Next.js app router, and interviewers often ask about it to evaluate candidate understanding of performance optimization.

Anti-pattern: Avoid putting heavy client-side code in loading.tsx, since it renders immediately on the server. The loading UI should be lightweight and not attempt to fetch additional data or use state hooks. If you need complex loading logic, consider using a client-side useEffect with a separate loading state, keeping the server-side loading.tsx simple and focused on instant UI feedback.

Real-world example: An e-commerce application uses loading.tsx to show skeleton screens while product data fetches. This reduces the perceived load time from 2-3 seconds to under 1 second, resulting in a 15% improvement in conversion rates. The skeleton screens match the product grid layout, providing a seamless transition from loading to rendered content.

Tools for testing: Use the webpack-bundle-analyzer and source map tools to understand the impact of loading.tsx on the final bundle. Monitor core web vitals (LCP, INP, CLS) before and after implementation to quantify the improvement. The impact is typically measured by the reduction in time-to-first-paint (TTFP) and time-to-interactive (TTI).

Recoverable Fallbacks with error.tsx

The error.tsx file (or error.js) catches render errors below it in the component hierarchy and shows a recoverable fallback UI. Unlike uncaught errors that crash the entire app, error.tsx allows the rest of the app to continue functioning. This is a critical feature for building reliable production applications, where a single component failure should not bring down the entire experience.

How it works: When a component rendered below error.tsx throws an error during rendering, Next.js catches it and renders the error.tsx for that segment instead of the normal UI. The error information (error message, stack, digest) is available as a prop. This mechanism provides a controlled way to handle errors without affecting the rest of the application.

Placement and inheritance:

  • app/dashboard/error.tsx catches errors for /dashboard and all its sub-routes.
  • app/dashboard/settings/error.tsx catches errors specifically for /dashboard/settings, taking precedence.
  • If a child has its own error.tsx, it takes priority; otherwise, the parent's error.tsx is shown.
  • Root app/error.tsx is the fallback for any uncaught error in the app. This is the outermost error boundary and handles errors that are not caught by any segment-specific error boundary.

Error prop: The error.tsx component receives a prop object with:

  • error — the caught error object. This includes the error message, stack trace, and any custom error properties.
  • digest — a string summarizing the error (useful for keys, logging). The digest is a concise summary that can be used as a consistent key across renders.
  • reset — a function to reset the error boundary and retry the failed component. When called, it re-renders the failed component and, if successful, removes the error boundary.
// app/dashboard/error.tsx
import { Button } from '@chakra-ui/react'
export default function DashboardError({
  error,
  digest,
  reset
}) {
  return (
    <div className="p-4 bg-red-100 text-red-800 rounded">
      <p>Something went wrong.</p>
      <p>{error.message}</p>
      <Button onClick={reset}>Try again</Button>
    </div>
  )
}

Recoverable vs. crash:

  • error.tsx is recoverable: clicking the reset button retries the failed component. This is the primary mechanism for recovering from errors without crashing the application.
  • Uncaught errors (no error.tsx) crash the route and potentially the entire app depending on the error boundary configuration. This is the default behavior if no error boundary is in place.

Interview framing: When asked about error.tsx, a strong answer explains that it catches render errors below it and shows a recoverable fallback with the error, digest, and reset props. Mentioning that it's segment-scoped (inherits the layout) and that it's different from global error handling (which would crash the app) shows depth. Discussing the reset function for retry behavior and the importance of graceful degradation demonstrates practical depth. Interviewers also appreciate candidates who can explain the trade-offs between recoverable and crash error handling.

Why it matters: The error.tsx feature directly improves application reliability. Instead of crashing the entire app when a single component fails, it allows the rest of the app to continue functioning. This is especially important for commerce applications, dashboards, and any application where uptime is critical. A single component failure should not bring down the entire page or application.

Anti-pattern: Avoid using error.tsx as a global catch-all without understanding the segment scoping. Each error.tsx is scoped to its segment and inherits the layout of that segment. Using the root app/error.tsx for every error can hide important segment-specific error information and make debugging more difficult. If you need to handle errors at the global level, consider whether segment-specific error boundaries are a better fit for your use case.

Real-world example: A SaaS application uses error.tsx to handle failures in the widget dashboard. When a widget component fails to load, the error boundary catches the error and shows a 'Try again' button. The user can click the button to retry, and the rest of the dashboard continues to function. This improves the user experience by keeping the dashboard functional even when individual widgets fail.

Tools for testing: Use the webpack-bundle-analyzer and source map tools to understand the impact of error.tsx on the final bundle. Monitor application error rates before and after implementation to quantify the improvement. Track the number of recovered errors vs. crashed routes to understand the effectiveness of the error boundary strategy.

Interview question: "Your application shows a crash page when a component fails. How do you make the error recoverable?" A strong answer: "I'd add error.tsx to catch the error and show a recoverable fallback with a reset button. This allows the user to retry without losing the rest of the application state. I'd also ensure the error boundary is segment-scoped so that only the affected section is impacted."

Typical interview scenario: An interviewer asks: "Your application shows a blank screen or crash when a component fails. How do you fix this?" A strong answer: "I'd add error.tsx to catch the error and show a recoverable fallback with a reset button. This is the standard approach for recoverable error handling in the Next.js app router."

Key takeaway: error.tsx is recoverable with a reset function; uncaught errors crash the route. The error boundary is segment-scoped and inherits the layout. The reset function retries the failed component.

Interview Framework for loading.tsx and error.tsx

When asked about loading.tsx and error.tsx, a strong answer covers the following areas:

loading.tsx:

  • Provides instant UI feedback during data fetching
  • Renders immediately while the server fetch is pending
  • Inherits parent layout (layouts persist across navigation)
  • Typical content: skeletons, spinners, simplified UI
  • Child segment takes precedence over parent
  • Improves core web vitals by reducing perceived load time

error.tsx:

  • Catches render errors below it
  • Shows recoverable fallback with error, digest, reset props
  • Segment-scoped (inherits the layout)
  • Uncaught errors crash the route
  • Reset function retries the failed component

Comparison: The key difference is that loading.tsx is proactive (renders while data is pending), while error.tsx is reactive (catches errors after they occur). Together, they form a complete error and loading strategy for the app router.

Interview quick answers:

  • What does loading.tsx do? — instant feedback during data fetch
  • How is error.tsx recoverable? — reset function retries the component
  • Difference between loading and error? — loading is proactive, error is recoverable
  • What does error.tsx inherit? — the segment's layout

Typical interview scenario: An interviewer asks: "Your application shows a blank screen while data loads, and crashes when a component fails. How do you fix this?" A strong answer: "I'd add loading.tsx for instant UI feedback during data fetching, and error.tsx for recoverable error handling. This combination provides the best user experience and application reliability."

Real-world example: An e-commerce application uses loading.tsx to show skeleton screens while product data fetches, and error.tsx to show a 'Try again' button when a product component fails to load. This combination reduces perceived load time and improves conversion rates by keeping the user in the flow instead of showing error pages. The result is a 10-15% improvement in conversion rates and a significant reduction in bounce rates.

Tools for testing: Use the webpack-bundle-analyzer and source map tools to understand the impact of loading.tsx and error.tsx on the final bundle. Monitor core web vitals (LCP, INP, CLS) before and after implementation to quantify the improvement. A typical improvement includes a 20-30% reduction in LCP and a 15-25% improvement in TTI.

Performance monitoring: Set up error tracking with tools like Sentry or LogRocket to monitor the effectiveness of error.tsx in production. Track the number of errors caught by the boundary vs. uncaught errors that crash the route. Monitor core web vitals before and after implementing loading.tsx to quantify the performance improvement.

Why the combination matters: The combination of loading.tsx and error.tsx provides the best user experience for a Next.js application. loading.tsx prevents the blank screen experience during normal data fetching, while error.tsx provides a recoverable fallback when something goes wrong. Together, they ensure that the application is both fast and reliable, which is essential for user retention and conversion.

Interview note: When discussing error handling in interviews, emphasize the proactive vs. reactive nature of loading.tsx and error.tsx. This demonstrates deep understanding of the app router's error and loading strategy, and shows you've thought about both the user experience during normal operation and the error handling strategy for unexpected situations.

Production considerations: In production, it's important to have proper error tracking and monitoring. Use tools like Sentry, LogRocket, or Cloudflare Observability to track errors and performance. Set up alerts for error rate spikes and performance degradation. This ensures that you can quickly identify and fix issues before they impact users.

Security consideration: Ensure that the error messages shown in error.tsx do not expose sensitive information such as API keys, database connection strings, or internal stack traces. The digest prop can be used to show a generic error message while still providing enough information for the user to understand what happened. The reset function should be carefully implemented to avoid re-introducing the same error.

Quiz

1. What does `loading.tsx` do in the app router?

Question 1 options

2. How does `error.tsx` differ from uncaught errors?

Question 2 options

3. What prop does `error.tsx` receive to retry the failed component?

Question 3 options

4. Which of the following is true about `loading.tsx` inheritance?

Question 4 options

Flashcards

Question

What does `loading.tsx` provide?

Answer

Instant UI feedback while a segment's data fetch is pending.

Question

What makes `error.tsx` different from uncaught errors?

Answer

Recoverable: shows fallback with `reset` function to retry; uncaught errors crash the route.

Question

What props does `error.tsx` receive?

Answer

`error` (the caught error), `digest` (string summary), `reset` (function to retry).

Question

Which loading.tsx takes precedence if both parent and child exist?

Answer

Child segment `loading.tsx` takes precedence.

Question

Where does `error.tsx` render relative to the error location?

Answer

It renders in place of the failed component, inheriting the segment's layout.

Revision Notes

Key Takeaways

  • 1. loading.tsx renders instantly while data fetch is pending
  • 2. Child loading.tsx takes precedence over parent
  • 3. Typical content: skeletons, spinners, simplified UI
  • 4. Inherits parent layout (layouts persist across navigation)
  • 5. error.tsx catches render errors below it
  • 6. Recoverable: shows fallback with error, digest, reset props
  • 7. Uncaught errors crash the route
  • 8. reset retries the failed component

Interview Tips

  • • What does loading.tsx do?—instant feedback during data fetch
  • • How is error.tsx recoverable?—reset function retries the component
  • • Difference between error.tsx and crash?—error.tsx shows fallback, crash exits
  • • What does error.tsx inherit?—the segment's layout

Cheat Sheet

loading.tsx and error.tsx Cheat Sheet

loading.tsx:

  • Renders instantly while data fetch is pending
  • Placement: segment-specific or root
  • Child loading.tsx takes precedence over parent
  • Typical content: skeletons, spinners, simplified UI
  • Inherits parent layout (layouts persist across navigation)

error.tsx:

  • Catches render errors below it
  • Shows fallback with error, digest, reset props
  • Segment-scoped (inherits the layout)
  • Uncaught errors crash the route
  • reset retries the failed component

Key difference: loading.tsx is proactive; error.tsx is reactive

Interview quick answers:

  • What does loading.tsx do?—instant feedback during data fetch
  • How is error.tsx recoverable?—reset function retries the component
  • Difference between loading and error?—loading is proactive, error is recoverable
  • What does error.tsx inherit?—the segment's layout

Continue Learning

Before You Start

Related Reading