• Skip to primary navigation
  • Skip to main content
  • Skip to footer

Codemotion Magazine

We code the future. Together

  • Discover
    • Events
    • Community
    • Partners
    • Become a partner
    • Hackathons
  • Magazine
    • Backend
    • Frontend
    • AI/ML
    • DevOps
    • Dev Life
    • Soft Skills
    • Infographics
  • Talent
    • Discover Talent
    • Jobs
    • Manifesto
  • Companies
  • For Business
    • EN
    • IT
    • ES
  • Sign in
ads

Antonello ZaniniJuly 24, 2023

How To Optimize Next.js for Production

Frontend
How to optimize Next.JS for production. Boost performance and user experience with this guide.
facebooktwitterlinkedinreddit

Next.js is now considered the framework for building the modern Internet. Its built-in features, server-side rendering capabilities, and seamless integration with React have made it a top 3 solution among developers. At the same time, tuning a Next.js production application requires some work to achieve high-level performance, short loading times, and an excellent user experience.

In this guide, you will dig into the essential strategies and best practices to deploy Next.js to production!

Recommended article
May 26, 2025

10 React expert tips that will change your life!

Lucilla Tomassi

Lucilla Tomassi

Frontend

7 Best Practices to Follow Before Deploying Next.js to Production

Let’s explore the most important best practice to optimize Next.js for production.

1. Take Advantage of Next.js’ Built-In Optimization Features

Next.js comes with built-in optimization features to take the performance of your production application to the next level. All you have to do to leverage them is to integrate them into your project, as explained in the documentation. These include:

  • Image Optimization: next/image exposes an <Image> component that extends the traditional HTML <img> element with automatic image optimization capabilities. In detail, it allows Next.js to:
    • Serve images in the best size depending on the user’s device.
    • Automatically convert them to modern image formats like WebP and AVIF.
    • Prevent layout shift errors when loading images in the frontend.
    • Load them only when they enter the viewport, using native browser lazy loading.
    • Resize images on-demand, even for remote files.
  • Font Optimization: next/font optimizes local fonts and removes external network requests for improved privacy and performance. As of Next.js 13, it supports self-hosting on any Google Font to avoid making requests to retrieve font files from Google.
  • Script Optimization: next/script offers a <Script> component that extends the traditional HTML <script> tag by allowing JavaScript scripts to be loaded only once across multiple pages.

2. Configure Caching and Use Incremental Static Regeneration Whenever Possible

Next.js treats file inside the /public folder as static assets. For example, if you store a logo.png image file in /public, you can then reference it in your code as /logo.png:

<Image src="/logo.png" alt="Company's Logo" width="200" height="200" />Code language: HTML, XML (xml)

Usually, /public contains static images, JavaScript, CSS, and other media files. Caching these resources is a good way to improve response times and reduce the number of requests required to render a page.

Here is why, by default, Next.js add the following header in production for those assets:

Cache-Control: public, max-age=31536000, immutableCode language: PHP (php)

This instructs the browser to cache those files for one year. So, if your Next.js site relies on some static resources, you should download and place them inside /public.

Next.js also provides the minimumCacheTTL configuration to specify the TTL (Time To Live) in seconds for caching images optimized through <Image>. Set it in next.config.js as follows:

// next.config.js

module.exports = {  
  images: {
    // cache optimized images for 60 seconds    
    minimumCacheTTL: 60,  
  },
}Code language: JavaScript (javascript)

Similarly, Next.js can cache statically generated pages through Incremental Static Regeneration (ISR). Thanks to this feature, new static pages can be created or updated after the application has been built.

To enable ISR, set the revalidate option in getStaticProps():

export async function getStaticProps() {
  // ... 
  return {
    props: {
      // ...
    },
    // Next.js will re-generate this page 
    // when a request comes in, at most once
    // every 10 seconds
    revalidate: 10, 
  }
}Code language: JavaScript (javascript)

This is how ISR works:

  1. The site initially shows the pre-rendered page generated at build time.
  2. Within 10 seconds, it will continue to display the initial page.
  3. When a request arrives after 10 seconds from the last regeneration, the framework triggers a background regeneration of the page.

Note that a Next.js production app only regenerates static pages that are requested by users to save resources.

3. Integrate an Analytics or APM Tool

Once a Next.js site is in production, you need a way to track its performance. In particular, you should have a system in place to monitor page views and get information about site traffic.

When deploying to Vercel, you can achieve that with Next.js Speed Insights. This tool allows you to analyze and measure the performance of your application’s pages using various metrics. To enable it:

  1. Turn on the Web Analytics option in the Vercel Dashboard.
  2. Add the @vercel/analytics package to your project’s dependencies with npm i @vercel/analytics
  3. Use the <Analytics /> component to inject the analytics script into your app.
  4. Deploy your app to Vercel, and data should start flowing to the Analytics view.

Similarly, you need a service that tracks site performance, alerts you when something goes wrong or the site goes offline, and collects information about bugs and runtime errors. This is what Application Monitoring (APM) is all about.

Some of the most popular APM libraries for Next.js are Sentry, New Relic, and AppSignal.

4. Set Up a Logging System

To keep track of what is going on in a Next.js production app, you must add some logs to your code. The easiest way to log messages on both the client and server is using the methods exposed by the JavaScript console object. The most popular ones are:

  • console.clear(): Clears the browser console.
  • console.log(): Logs general information.
  • console.debug(): Logs a debug message in the browser console and a regular message on the server.
  • console.error(): Logs an error message.
  • console.warn(): Logs a warning message in the browser console or an error message on the server
  • console.time(): Starts a timer that can be used to compute the duration of an operation.
  • console.timeEnd(): Stops the timer and prints the duration of the operation.

If you instead prefer a more structured solution, Next.js recommends pino. This is a fast and lightweight JavaScript logging library designed for high-performance applications.

5. Enable Error Handling With Custom 500 and 400 Pages

Like any other application, Next.js sites are subject to errors. One of the most important aspects of error handling is presenting meaningful error messages to users to inform them of what happened. When an error occurs in the frontend or backend, Next.js displays this static 500 page:

The Next.js default 500 page
The Next.js default 500 page

As you can see, this page is not informative at all and may result in a bad user experience for visitors. This is why Next.js supports custom 500 pages.

If you are a Pages Router user, create a 500.js page under /pages:

// pages/500.js

export default function Custom500Page() {  
  // your custom 500 page component.... 
}Code language: JavaScript (javascript)

This represents the frontend page components that will be shown to users in case of errors.

If you are an App Router user, create an error.js file under /app:

// app/error.js

'use client' // error components must be client components
  
export default function CustomErrorPage({
  error,
  reset,
}) {
  // your custom error page component.... 
}Code language: JavaScript (javascript)

Note that this must be a client component.

Next.js also supports a static 404 page, which is rendered:

  • When the object returned by getStaticProps() or getServerSideProps() contains notFound: true in a Pages Router app.
  • When the notFound() function is called in an App Router app.

Again, the default 404 page is not the best:

The Next.js default 404 page
The Next.js default 404 page

To customize it, if you are a Pages Router user, create a 404.js page under /pages:

// pages/404.js

export default function Custom404Page() {
  // your custom 404 error page component.... 
}Code language: JavaScript (javascript)

If you are an App Router user, define a not-found.js file under /app:

// app/not-found.js
  
export default function NotFoundPage() {
  // your custom 404 error page component.... 
}Code language: JavaScript (javascript)

6. Reduce the Size of the Build Bundle

Producing a minimized bundle is great, as clients will take less time and network bandwidth to download and render the Next.js production app.

During the next build task, Next.js generates an optimized JavaScript bundle for each page.
The goal is to try to reduce those bundles to the bare while preserving functionality. For this purpose, you can use dynamic imports via next/dynamic to lazy-load JavaScript resources. This mechanism allows you to defer loading specific components or libraries until the user performs a particular operation on the page.

To analyze the bundle produced by Next.js and get guidance on how to reduce its size, you can use the following tools:

  • Webpack Bundle Analyzer: To visually explore the size of webpack output files in an interactive treemap.
  • Package Phobia: To analyze the cost of adding a new dependency to your project.
  • Bundle Phobia: To analyze how much a dependency will increase the bundle size.
  • bundlejs: To quickly bundle and minify your project in your browser.
  • Import Cost: To display the size of any imported package inside Visual Studio Code.

7. Optimize Page SEO Performance With Lighthouse

The ultimate goal of most Next.js sites is to produce excellent SEO results. Google has changed its approach to SEO performance evaluation a great deal over time, and it now focuses primarily on Core Web Vitals:

  • Largest Contentful Paint (LCP): Measures the time it takes for the main content of a page to become visible to users.
  • First Input Delay (FID): Evaluates the time delay between a user’s first interaction and the browser’s response.
  • Cumulative Layout Shift (CLS): Gauges the visual stability of a page by measuring the number of unexpected layout shifts that may annoy users.

Recommended article: React Libraries for Boosting UI Design

These represent user experience metrics that Google uses to assess and quantify the overall performance of web pages and define their ranking in search results.

The best tool for optimizing these indicators is Google Lighthouse, an open-source tool built into Chrome that can be run on any web page to check its SEO performance.

To optimize Next.js for production, you should build the project, start it, open it in Incognito mode in the browser, and launch Lighthouse on each page. This will provide guidance and best practices for improving site performance, accessibility, and SEO.

Conclusion

In this article, you looked at what to do to make a Next.js application production-ready. As you learned here, this involves enabling caching, using the advanced built-in optimization features, and setting up a performance logging and monitoring system.

Through several examples and insights, you had the opportunity to see how to build a reliable Next.js production site. Deploying a top-notch site has never been easier!

Thanks for reading! We hope you found this article helpful!

Related Posts

Native CSS: A Whole New Story – Part 1

Daniele Carta
March 3, 2025

Understanding Angular — Exploring Dependency Injection and Design Patterns — Part 0 🔥🚀

Giorgio Galassi
February 5, 2025

Let’s Create a Bento Box Design Layout Using Modern CSS

Massimo Avvisati
January 21, 2025
React library: all you need to know about it.

Building reusable multiple-step form in ReactJS

Noa Shtang
August 8, 2024
Share on:facebooktwitterlinkedinreddit
Antonello Zanini
I'm a software engineer, but I prefer to call myself a Technology Bishop. Spreading knowledge through writing is my mission.
What is Just-In-Time (JIT) Permission Management, and Why is it Essential? 
Previous Post
Data Analysis Made Easy: Mastering Pandas for Insightful Results
Next Post

Footer

Discover

  • Events
  • Community
  • Partners
  • Become a partner
  • Hackathons

Magazine

  • Tech articles

Talent

  • Discover talent
  • Jobs

Companies

  • Discover companies

For Business

  • Codemotion for companies

About

  • About us
  • Become a contributor
  • Work with us
  • Contact us

Follow Us

© Copyright Codemotion srl Via Marsala, 29/H, 00185 Roma P.IVA 12392791005 | Privacy policy | Terms and conditions