
Optimizing Web Vitals in Next.js for Better Performance
- Author: Md. Saad
- Published at: August 18, 2024
- Updated at: August 18, 2024
Introduction
Web Vitals are a set of metrics introduced by Google to measure and quantify key aspects of user experience on the web. These metrics focus on aspects of web performance that directly impact the user experience, such as loading times, interactivity, and visual stability. The goal is to provide web developers with clear guidance on improving the quality of the user experience on their sites.
Next Js has introduced several built-in components to improve the core web vitals. These are next/image, Dynamic Imports, next/script and next/font. Let’s discuss all of them.
Next.js Image Component
The next/image is a Next.js image component that can automatically optimize images. Using this method we can acquire Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS) by resizing, compressing, and lazy-loading them. Additionally, it can be used to show images that are responsive to various screen widths. Thus, it helps to achieve good Core Web Vitals. Let’s see some examples:
- Use next/image: This component automatically optimizes images, which can greatly improve LCP.
import Image from 'next/image';
import profilePic from "../public/me.png";
export default function Home() {
return (
<div>
<Image src={profilePic} alt="Large Image" />
</div>
);
}
We have imported the image from Next Js next/image into this example. And use the Image tag to show the image instead of using the default img tag.
- Always specify the width and height for Images and Videos to Enhance Cumulative Layout Shift (CLS).
import Image from 'next/image';
import profilePic from "../public/me.png";
export default function Home() {
return (
<div>
<Image src={profilePic} alt="Large Image" width={800} height={600} />
</div>
);
}
In this example, we have added width and height properties to the Image tag that eventually improve our Cumulative Layout Shift (CLS).
We can also use other's next/image functionality to improve our Web Vital Value. To learn more about next/image, you can read this article.
Next.js Script Component
We often use third-party scripts to include different types of functionality in our application. These scripts overlook the performance impact on the website. Furthermore, a developer who uses this may find it very difficult to optimize them. The next/script component can help them to solve this problem. Using this third-party scripts can be loaded asynchronously. Additionally, it can be used to defer loading non-essential scripts. Thus, These techniques can improve metrics like First Input Delay (FID) and Interaction To Next Paint (INP). let’s see an example:
Using regular HTML, external scripts would need to be manually appended to next/head:
import Head from 'next/head';
function IndexPage() {
return (
<div>
<Head>
<script src="https://www.googletagmanager.com/gtag/js?id=123" />
</Head>
</div>
);
}
With the Next.js Script component, we do not need to use next/head anymore. In fact, we can add it anywhere in the component :
import Script from 'next/script';
function IndexPage() {
return (
<div>
<Script
strategy="afterInteractive"
src="https://www.googletagmanager.com/gtag/js?id=123"
/>
</div>
);
}
A strategy attribute introduced by the Script component lets us choose when to fetch and run a script for the best loading experience.
The strategy attribute can take three values:
- beforeInteractive: For crucial scripts that need to run before the page becomes interactive, this option could be utilized. Next.Js makes sure that these scripts are run before other self-bundled JavaScript by injecting them into the server's initial HTML. This tactic works well for consent management, scripts for bot identification, or utility libraries needed to render important material.
- afterInteractive: This is the default approach used, which is the same as loading a script that has the defer attribute applied to it.
- lazyOnloadExternal: With this option, you can leverage the browser's idle time to load low-priority scripts hosted on external servers. This approach works best when scripts can be loaded after the first-page load and are not necessary for the page to appear. One instance of this is the loading of advertisement scripts during the user's idle period following the initial page load.
Most third-party scripts should be delayed to load after all page contents have loaded to avoid negatively affecting Largest Contentful Paint (LCP). This can be done either immediately after the page becomes interactive (strategy="afterInteractive") or sluggishly during browser idle time (strategy="lazyOnload").
Using Dynamic Imports
We can also improve core web vitals rank using Next js Dynamic Imports. We can dynamically import components or heavy libraries (import('component')) to reduce the amount of JavaScript that needs to be executed on the initial load.
There are two ways you can implement lazy loading in Next.js:
- Using dynamic imports with the next/dynamic package.
- Using a combination of React.lazy() and Suspense.
To learn more about the dynamic import, read this article.
Optimizing Fonts
next/font will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance. For any font file, next/font offers integrated automated self-hosting. This indicates that we can load web fonts efficiently with zero layout shifts. Thus, Next Js next/font components can be used to increase page speed and visual stability by preventing layout shifts (CLS) caused by font loading. Let’s have an example:
Suppose we want to use a Roboto font.
- Get started by importing the Roboto font to use from next/font/google as a function. Next Js recommend using variable fonts for the best performance and flexibility.
import { Roboto } from 'next/font/google'- Now create a javascript function which returns value will be a class name you can leverage in your component template. If you can't use a variable font, you will need to specify a weight. Also, remember to add display: swap to the configuration object to enable the feature.
import { Roboto } from 'next/font/google'
// If loading a variable font, you don't need to specify the font weight
const roboto = Roboto({
weight: '400',
subsets: ['latin'],
display: 'swap',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={roboto.className}>
<body>{children}</body>
</html>
)
}In this way, we can use next/font to load fonts efficiently. To read more about next/font, you can follow this link.
Conclusion
Optimizing Core Web Vitals in Next.js is essential for enhancing user experience, improving performance, and boosting SEO. Implementing these optimizations will significantly improve your Next.js app's Core Web Vitals, resulting in a faster, more responsive, and stable user experience.
To get help on any next.js issues, feel free to contact us.