Next JS Error Handling


Error handling in Next.js is crucial for providing a good user experience and maintaining a robust application. Next.js provides several built-in mechanisms to handle errors in both the server-side and client-side contexts, allowing developers to catch, display, and handle errors gracefully.

1. Error Handling in Pages

Next.js has a built-in mechanism for displaying error pages for specific types of errors. Here are the main methods:

a. Built-in Error Pages

Next.js provides two default error pages for common scenarios:

  • 404 Page: The 404.js file in the pages directory can be customized to handle "Page Not Found" errors.
  • 500 Page: You can create a 500.js page in the pages directory to handle internal server errors.

For example:

// pages/404.js const Custom404 = () => { return ( <div> <h1>404 - Page Not Found</h1> <p>Sorry, the page you're looking for does not exist.</p> </div> ); }; export default Custom404;

By default, if these pages are not defined, Next.js provides a generic fallback error message.

b. getInitialProps and Error Handling

If your page uses getInitialProps, you can handle errors in this function to pass error-related props to your component.

// pages/_error.js import React from 'react'; const Error = ({ statusCode }) => { return ( <p> {statusCode ? `An error ${statusCode} occurred on server` : 'An error occurred on client'} </p> ); }; Error.getInitialProps = ({ res, err }) => { const statusCode = res ? res.statusCode : err ? err.statusCode : 404; return { statusCode }; }; export default Error;

The _error.js page acts as a global error handler for both server and client errors.

2. Custom Error Pages

You can create a custom error page by adding a file named _error.js in the pages directory. This page will handle all uncaught exceptions, including server-side and client-side errors.

Example:

// pages/_error.js import React from 'react'; const CustomErrorPage = ({ statusCode }) => { return ( <div> <h1>{statusCode ? `Error ${statusCode}` : 'An error occurred'}</h1> <p>Something went wrong. Please try again later.</p> </div> ); }; CustomErrorPage.getInitialProps = ({ res, err }) => { const statusCode = res ? res.statusCode : err ? err.statusCode : 404; return { statusCode }; }; export default CustomErrorPage;
  • This _error.js page can be used to handle and customize server-side and client-side error messages.
  • The getInitialProps function allows passing a statusCode to the component to indicate the type of error.

3. Error Boundaries

For client-side error handling, you can create Error Boundaries. React itself does not have a built-in feature for this, but Next.js allows using standard React error boundaries for catching JavaScript errors in components.

  • Example of an Error Boundary:
    import React from 'react'; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state so the next render shows the fallback UI. return { hasError: true }; } componentDidCatch(error, errorInfo) { // Log the error to an error reporting service console.error('Error caught by ErrorBoundary:', error, errorInfo); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; } } export default ErrorBoundary;
  • You can then use this ErrorBoundary component to wrap other components:
    import ErrorBoundary from '../components/ErrorBoundary'; const HomePage = () => { return ( <ErrorBoundary> <div>Welcome to the homepage!</div> </ErrorBoundary> ); }; export default HomePage;

This way, any error within the components inside ErrorBoundary will be caught, and the fallback UI will be shown.

4. Try-Catch Blocks for API Calls

For handling errors during API calls or asynchronous data fetching in client-side code, try-catch blocks are commonly used. This approach is useful for data fetching functions like getServerSideProps, getStaticProps, or client-side API requests.

  • Example with getServerSideProps:
    export async function getServerSideProps(context) { try { const res = await fetch('https://api.example.com/data'); if (!res.ok) { throw new Error('Failed to fetch data'); } const data = await res.json(); return { props: { data } }; } catch (error) { console.error('Error fetching data:', error); return { props: { error: 'Failed to load data. Please try again later.' }, }; } } const Page = ({ data, error }) => { if (error) { return <div>{error}</div>; } return <div>Data: {data}</div>; }; export default Page;

This example demonstrates how to catch errors during server-side data fetching and provide a fallback response.

5. Error Handling in API Routes

For Next.js API routes (pages/api), you need to handle errors by sending appropriate responses.

  • Example API route with error handling:
    // pages/api/user.js export default async function handler(req, res) { try { // Simulate fetching data from an external source if (req.method !== 'GET') { throw new Error('Only GET requests are supported'); } const userData = { id: 1, name: 'John Doe' }; res.status(200).json(userData); } catch (error) { console.error('API Error:', error); res.status(500).json({ error: 'Internal Server Error' }); } }

In this example, errors in the API route are caught and logged, and the response is sent back with an appropriate status code.

6. Middleware for Error Handling

With middleware in Next.js, you can control global redirection and response behavior, potentially handling errors at the routing level.

  • Example:
    // middleware.js import { NextResponse } from 'next/server'; export function middleware(req) { try { const { pathname } = req.nextUrl; if (pathname.startsWith('/admin')) { const isAuthenticated = false; // Replace with real authentication logic if (!isAuthenticated) { return NextResponse.redirect('/login'); } } } catch (error) { console.error('Middleware Error:', error); return NextResponse.redirect('/500'); } }

In this middleware, redirection occurs when the user is not authenticated, and any errors caught are redirected to a custom error page.

Summary

  • Built-in Error Pages (404 and 500): Next.js provides default error pages that can be customized for common scenarios.
  • Custom Error Page (_error.js): This page can be used to handle uncaught exceptions and customize error messages globally.
  • Error Boundaries: Used for handling client-side errors in components, providing a graceful fallback UI.
  • try-catch for Data Fetching: Handle errors in getServerSideProps, getStaticProps, or client-side functions with try-catch blocks.
  • API Routes: Handle errors in API routes by sending appropriate response codes.
  • Middleware: Control routing errors and provide appropriate redirections.

Next.js offers a wide range of options for managing and handling errors both on the server-side and client-side, ensuring that errors are caught and handled gracefully to improve user experience and maintain application stability.