Any program must include error management, but it becomes even more important in production settings where system integrity, user experience, and dependability are critical. When failures are handled well in Next.js, your application will be reliable, give users insightful feedback, and assist developers in finding solutions more rapidly. We’ll go into some best practices for Next.js applications’ error handling in this blog.
1. Distinguish Between Server-Side and Client-Side Errors in Next.js
Since Next.js functions both on the client and server sides, several error-handling techniques are needed depending on the situation. To address an error correctly, you must identify its source.
- Server-Side Errors: These occur during data fetching, API requests, or server-rendered pages.
- Client-Side Errors: These occur within the browser due to user interactions, network issues, or other client-only operations.
You can distinguish between the two by using try-catch blocks on the server side or leveraging React error boundaries on the client side.
Example (server-side)
export async function getServerSideProps(context) {
try {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { data } };
} catch (error) {
console.error('Server-side error:', error);
return {
notFound: true, // This renders a 404 page in case of an error.
};
}
}
Example (client-side)
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const res = await fetch('/api/data');
const json = await res.json();
setData(json);
} catch (error) {
console.error('Client-side error:', error);
}
}
fetchData();
}, []);
return data ? <div>{data}</div> : <div>Loading...</div>;
}
2. Use for getInitialProps / getServerSideProps Server-Side Errors
You can use getServerSideProps (for custom _app.js) or getInitialProps (for server-side rendering of pages) in Next.js to manage and report server-side issues. This allows you to render a fallback page, redirect the user, or return error statuses.
Example
export async function getServerSideProps(context) {
try {
const res = await fetch(`https://api.example.com/resource`);
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' } };
}
}
3. Error Boundaries in Next.js
Thanks to Next.js’s React foundation, you can use error boundaries to identify and track JavaScript faults that occur anywhere in your component tree and display fallback user interface (UI) without crashing the entire application.
Error boundaries can be used to catch client-side errors but won’t work for server-side rendering (SSR). You can create a wrapper component for error boundaries:
Example
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught by Error Boundary:', error, errorInfo);
// You can log the error to an error reporting service here
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
4. Custom Error Pages in Next.js
Custom error pages are a built-in method of handling 404 and 500 problems in Next.js. You can override the default Next.js error page rendering by creating a pages/_error.js file. This enables you to personalize the error message and provide consumers constructive criticism when something goes wrong.
Example
import React from 'react';
function Error({ statusCode }) {
return (
<div>
<h1>{statusCode ? `An error ${statusCode} occurred` : 'An unexpected error occurred'}</h1>
</div>
);
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
return { statusCode };
};
export default Error;
5. Global Error Logging in Next.js
Error reporting is essential for monitoring and troubleshooting problems in production. Stack traces, user behaviors preceding the problem, and other debugging data can be captured with the use of integration tools such as Sentry, LogRocket, or New Relic.
Here’s how to integrate Sentry for logging:
Example
// sentry.client.config.js
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: 'https://your_dsn@sentry.io/project_id',
tracesSampleRate: 1.0,
});
6. Graceful Fallbacks for Data Fetching in Next.js
It’s crucial to have fallbacks in place in Next.js applications for data fetching in case the request fails. You can retry the call with default data or with a loading/error state displayed.
Example
export async function getServerSideProps() {
try {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { data } };
} catch (error) {
console.error('Error fetching data:', error);
return { props: { data: null } };
}
}
function Page({ data }) {
if (!data) {
return <div>Error loading data, please try again later.</div>;
}
return <div>{data.title}</div>;
}
7. Graceful Error Handling in API Routes
Next’s API routes.Another crucial area that requires strong error handling is JavaScript. Try-catch blocks should be used to encapsulate your API code and provide insightful error answers.
Example
export default async function handler(req, res) {
try {
const result = await someAsyncOperation();
res.status(200).json({ success: true, data: result });
} catch (error) {
console.error('API error:', error);
res.status(500).json({ success: false, message: 'Internal Server Error' });
}
}
8. Use Status Codes Properly in Next.js
When handling server-side errors or creating custom API routes, always ensure that the correct HTTP status codes are returned. For example:
- 404 for not found
- 500 for internal server errors
- 403 for forbidden access
- 401 for unauthorized access
This improves clarity when debugging and ensures that users and developers alike receive meaningful feedback about what went wrong.
Example
export async function getServerSideProps(context) {
const { id } = context.params;
const res = await fetch(`https://api.example.com/resource/${id}`);
if (res.status === 404) {
return {
notFound: true,
};
}
const data = await res.json();
return { props: { data } };
}
Conclusion
Next.js error handling calls for careful consideration, particularly in light of the combination of server-side and client-side execution environments. You may create an application that is more robust and user-friendly by utilizing these best practices, which include identifying different sorts of failures, utilizing error boundaries, personalizing error pages, logging errors, and addressing API errors.
Finally, for more such updates and to read more about such topics, please follow our LinkedIn page Frontend Competency.