DEV Community

Cover image for Error handling in Next.js App Router
Syket Bhattachergee
Syket Bhattachergee

Posted on

Error handling in Next.js App Router

If you've been working with Next.js 14 and you've spotted the error.js file in your directory, you might be wondering what it's all about. Well, you're in luck! Today, we're going to break down this file and see how it helps us out.

First of all, let's understand how the error file works. The error.js file convention allows you to gracefully handle unexpected runtime errors in nested routes.

  • Automatically protect each part of your route along with its nested parts using a React Error Boundary.
  • Design error displays are customized for each section by organizing files in a hierarchy.
  • Contain errors within specific sections while keeping the rest of your app running smoothly.
  • Implement features to try fixing errors without reloading the entire page.

One of the most important things is that the error.js file should be a client-side component. There is no option to make it a server-side component, as specified in the Next.js documentation. Let's look at the code of the error.js file:

'use client' // Error components must be Client Components

import { useEffect } from 'react'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // Attempt to recover by trying to re-render the segment
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Here is an overview of how error.js file work:

How error.js file work in next.js

error.js creates a React Error Boundary around a specific component or page.js. It uses the exported React component from error.js as a backup. If an error occurs within this boundary, it's isolated, and the backup component is shown. Despite the error, layouts above the boundary stay functional, allowing for error recovery options within the backup component.

Recovering From Errors

If an error is temporary, retrying might fix it. Using the reset() function in an error component prompts users to try again. When reset() the Error Boundary attempts to re-render its contents. If successful, the fallback error component is replaced with the new result.

'use client'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Nested Routes

Nested Routes in React involve rendering components in a structured hierarchy.

For instance, consider a scenario where two nested segments each contain layout.js and error.js files. This creates a hierarchy like this:

Nested Error Component Hierarchy

  • Errors propagate upwards to the nearest parent error boundary. This means that an error.js file will manage errors for all its nested child segments.
  • Adjustments to the granularity of error UI are possible by positioning error.js files at various levels within the nested route folders.
  • However, an error boundary defined in an error.js file won't handle errors from a layout.js component in the same segment, as the error boundary is nested within that layout's component.

Handling Errors in Layouts

Error boundaries defined error.js do not capture errors occurring in layout.js or template.js components within the same segment. This hierarchy is deliberate, ensuring that crucial UI elements shared among sibling routes, like navigation, remain accessible and usable during errors.

To manage errors within a particular layout or template, include an error.js file in the parent segment of that layout.

For handling errors within the root layout or template, utilize a variant named global-error.js.

When dealing with errors in root layouts:

  • The root app/error.js boundary doesn't handle errors from root app/layout.js or app/template.js components.
  • For handling errors in these root components, utilize a variant named app/global-error.js, placed in the root app directory.
  • Unlike app/error.js, global-error.js wraps the entire application, replacing the root layout with its fallback component when active. Thus, global-error.js must include its own and tags.
  • global-error.js serves as broad error handling for the entire application, less frequently triggered due to the static nature of root components. However, it's still advisable to have a root error.js file defining a fallback component within the root layout for consistent UI and branding.
  // app/global-error.tsx

  'use client'

  export default function GlobalError({
    error,
    reset,
  }: {
    error: Error & { digest?: string }
    reset: () => void
  }) {
    return (
      <html>
        <body>
          <h2>Something went wrong!</h2>
          <button onClick={() => reset()}>Try again</button>
        </body>
      </html>
    )
  }
Enter fullscreen mode Exit fullscreen mode

Handling Server Errors

When a Server Component encounters an error, Next.js forwards an Error object (with sensitive details removed in production) to the nearest error.js file as the error prop.

To protect sensitive data, in production, only a generic message and a digest property are sent to the client. The digest is a hash of the error useful for matching with server-side logs.

In development, the Error object sent to the client includes the original error message for easier debugging.

Conclusion

In conclusion, error files, such as error.js or global-error.js, serve as crucial components in React applications for defining error UI boundaries within route segments. They effectively catch unexpected errors, whether originating from Server Components or Client Components and display fallback UI to maintain a smooth user experience. These files offer functionalities like resetting error boundaries and ensuring error handling consistency throughout the application. Additionally, the distinction between error.js and global-error.js provides flexibility in managing errors at different levels, from specific layouts to the root application. By adhering to best practices and leveraging tools like React Developer Tools, developers can optimize error-handling mechanisms to enhance the reliability and usability of their React applications.

About me

I am Syket Bhattachergee, Software Engineer at CreoWis. If you want to discuss your technical writing needs or any role? You can reach out to me on LinkedIn or My Website, and follow my work on GitHub.

Top comments (3)

Collapse
 
matin_mollapur profile image
Matin Mollapur

Great article! I've been struggling with error handling in Next.js, and this breakdown of error.js is super helpful. Love how you explained the nested routes and layout errors - that was a bit confusing for me before. Definitely bookmarking this for future reference. Thanks for making it so clear and easy to understand!

Collapse
 
syketb profile image
Syket Bhattachergee

@matin_mollapur Thanks, I am happy to see that you loved it. This is my job to spread my knowledge whatever I have learned in the tech industry, keep me in your prayers, I want to do it more and more. Thanks again.

Collapse
 
matin_mollapur profile image
Matin Mollapur

πŸ‘