In the modern web development world, speed is not just an advantage, it's a necessity. A slow-loading website not only frustrates users but is also penalized by search engines like Google, directly affecting SEO rankings and revenue. Fortunately, with Next.js, we are equipped with extremely powerful tools to tackle core performance issues.
This article dives into the three main culprits of slow websites: Images, Fonts, and third-party Scripts. We'll explore how to tame them using Next.js's specialized components: next/image
, next/font
, and next/script
. Get ready to take your Next.js app to the next level in speed and user experience! ⚡️
1. next/image: The Image Optimization "Wizard" 🖼️
Images are often the heaviest assets on a web page. Loading a 5MB photo for a mobile screen is a huge waste of resources. The next/image
component was created to solve this problem intelligently and automatically. It's not just a regular <img>
tag, but a comprehensive image optimization engine.
The Problems with Traditional <img>
Tags
The <img>
tag has several weaknesses if not optimized:
- Loads original size: Loads a 4K image for a 300px-wide
div
, wasting bandwidth. - No default lazy loading: All images are loaded immediately, even those at the bottom of the page, slowing down initial load.
- Layout Shift (CLS): The browser doesn't know the image size until it's loaded, causing annoying "page jumps" as content shifts.
- No automatic format conversion: Doesn't take advantage of modern formats like WebP or AVIF for better compression.
The Power of next/image
next/image
solves all these issues "magically":
- Automatic Resizing: Next.js automatically generates multiple versions of an image at different sizes and serves the most appropriate one for the user's device.
- Default Lazy Loading: Images are only loaded when the user scrolls near them, significantly speeding up initial page load.
- Prevents Layout Shift: By requiring
width
andheight
,next/image
reserves space for the image before it loads, eliminating Cumulative Layout Shift (CLS). - Modern Image Formats: Automatically serves images in WebP or AVIF if the browser supports them, reducing file size without sacrificing quality.
- Priority Loading: For important above-the-fold images (like hero banners), you can add the
priority
prop to tell Next.js to load them first, greatly improving Largest Contentful Paint (LCP).
How to Use next/image
Effectively
For local images (in public
or src
):
import Image from 'next/image'
import heroBanner from '../public/images/hero-banner.jpg'
function HomePage() {
return (
<Image
src={heroBanner}
alt="Image description"
width={1200}
height={600}
priority // Prioritize for LCP
placeholder="blur" // Blur effect while loading
// sizes helps the browser pick the right image for different screen sizes
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
)
}
For external images (CDN):
First, configure the image domain in next.config.js
:
// next.config.js
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.unsplash.com',
port: '',
pathname: '/**',
},
],
},
}
Then use it in your component:
import Image from 'next/image'
function PostCard({ post }) {
return (
<Image
src={post.imageUrl} // "https://images.unsplash.com/photo-..."
alt={post.title}
width={500}
height={300}
loading="lazy" // Default, but can be explicit
/>
)
}
💡 Pro Tip: Always provide accurate
width
andheight
. Use thesizes
prop to optimize image selection for different devices and usepriority
for the most important image on the page.
2. next/font: Font Solution Without Layout Shift ✍️
Web fonts are beautiful, but they can cause performance issues like Flash of Invisible Text (FOIT) or Flash of Unstyled Text (FOUT), and worse, layout shift when the font loads and replaces the system font.
next/font
is a revolution in font management. It automatically optimizes and self-hosts your fonts, eliminating these issues.
Outstanding Benefits of next/font
Why you should use next/font
right away:
- Automatic Self-hosting: Instead of fetching from Google Fonts on every page load,
next/font
downloads the font and serves it with your static assets. This removes a network round-trip, reducing render-blocking time. - Zero Layout Shift: This is the killer feature.
next/font
uses the CSSsize-adjust
property to make the fallback system font occupy the exact same space as the web font. The result? When the web font loads, there is no shift at all. - High Performance:
next/font
automatically addsfont-display: optional;
(orswap
) to CSS, so the browser displays text immediately with the fallback font.
How to Use next/font
With Google Fonts:
// In your layout.js or _app.js
import { Inter, Roboto_Mono } from 'next/font/google'
// Initialize fonts with options
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter', // Use with CSS Variables
})
const robotoMono = Roboto_Mono({
subsets: ['latin'],
display: 'swap',
variable: '--font-roboto-mono',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={`${inter.variable} ${robotoMono.variable}`}>
<body>{children}</body>
</html>
)
}
Then in your globals.css
:
body {
font-family: var(--font-inter), sans-serif;
}
h1,
h2,
code {
font-family: var(--font-roboto-mono), monospace;
}
With Local Fonts:
// In your layout.js or _app.js
import localFont from 'next/font/local'
const myFont = localFont({
src: './MyCustomFont.woff2',
display: 'swap',
variable: '--font-my-custom',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={myFont.variable}>
<body>{children}</body>
</html>
)
}
💡 Pro Tip: Always use
next/font
instead of the traditional<link>
tag in_document.js
for fonts. It brings performance and UX benefits with minimal configuration.
3. next/script: The "Conductor" for Third-Party Scripts 📜
Third-party scripts (analytics, chatbots, ads, Google Tag Manager) are among the top causes of slow websites and high Total Blocking Time (TBT). They often block the main thread, delaying user interaction.
The next/script
component lets you precisely control when and how these scripts are loaded and executed.
Loading Strategies
next/script
provides a powerful strategy
prop:
strategy="beforeInteractive"
:- When to use: Only for scripts that are absolutely critical and must run before the page is interactive, such as cookie consent managers.
- Note: Use with caution as it can block page rendering.
strategy="afterInteractive"
(Default):- When to use: Perfect for most scripts. The script loads and runs right after the page becomes interactive (hydrated).
- Example: Google Analytics, Google Tag Manager.
strategy="lazyOnload"
:- When to use: For low-priority scripts that can wait until all other resources are loaded and the browser is idle.
- Example: Chatbots (Intercom, Crisp), social widgets.
How to Use next/script
import Script from 'next/script'
function MyPage() {
return (
<div>
<h1>My Page</h1>
{/* Google Tag Manager - Load after page is interactive */}
<Script
src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
strategy="afterInteractive"
/></Script>
{/* Intercom Chat Widget - Load when browser is idle */}
<Script
src="https://widget.intercom.io/widget/APP_ID"
strategy="lazyOnload"
/>
)
}
Advanced Optimization with Web Workers (Partytown)
For heavy scripts, you can offload them from the main thread entirely by running them in a Web Worker. Next.js integrates with Partytown to make this easy.
To enable, in next.config.js
:
// next.config.js
module.exports = {
experimental: {
workerThreads: true,
cpus: 1, // Limit number of workers to save resources
},
}
Then use strategy="worker"
:
<Script src="https://example.com/heavy-script.js" strategy="worker" />
This shifts the script's processing load to a background thread, keeping your UI smooth and responsive.
Conclusion: Optimization is an Ongoing Process
Optimization is not a one-time job, but a continuous process. However, by mastering and applying these three powerful tools that Next.js provides:
next/image
: For fast, lightweight, layout-shift-free images.next/font
: For beautiful fonts without sacrificing performance or user experience.next/script
: For controlling third-party scripts and keeping the main thread clear.
You have the toolkit needed to build web apps that are not only beautiful and feature-rich but also blazingly fast. Start reviewing your project today and apply these techniques—you'll see a clear difference in tools like PageSpeed Insights, and more importantly, in your users' satisfaction.