Image and Font Optimization

intermediate
11 min

Image and Font Optimization

Images are usually the heaviest assets on a page, and web fonts are a classic cause of layout jank. Next.js ships dedicated tools for both: the Image component and the next/font module. Used correctly, they noticeably improve Core Web Vitals - which affects both user experience and search ranking.

The Problem with a Plain img Tag

A plain img tag ships the original file at its original size to every device, can shift the layout when it loads, and loads even when it is far below the fold. The Next.js Image component fixes all three automatically.

Using next/image

jsx
import Image from 'next/image'; import hero from '@/public/hero.jpg'; export default function Hero() { return ( <Image src={hero} alt='Developer working on a laptop' priority className='rounded-xl' /> ); }

What you get automatically:

  • Resizing: multiple sizes are generated and the browser picks the right one via srcset.
  • Modern formats: images are served as WebP or AVIF when the browser supports them.
  • Lazy loading: off-screen images load only as they approach the viewport.
  • No layout shift: width and height are inferred from the static import, so space is reserved before the image loads.

For local images imported like above, dimensions are automatic. For remote images you must supply width and height yourself and allow the domain in next.config.mjs:

js
// next.config.mjs const nextConfig = { images: { remotePatterns: [ { protocol: 'https', hostname: 'images.unsplash.com' }, ], }, }; export default nextConfig;

Fill Mode and Sizes

When an image should stretch to its container - a card thumbnail, a banner - use fill with a positioned parent:

jsx
<div style={{ position: 'relative', height: 300 }}> <Image src='/banner.jpg' alt='' fill style={{ objectFit: 'cover' }} sizes='(max-width: 768px) 100vw, 50vw' /> </div>

The sizes attribute tells the browser how wide the image will render so it downloads the smallest sufficient file. Two more tips: add priority to the largest above-the-fold image (usually your hero) so it is not lazy-loaded, and always write meaningful alt text for accessibility and SEO.

Font Optimization with next/font

Loading Google Fonts from a CDN link adds an extra network round-trip and can flash unstyled text. next/font downloads the font at build time and serves it from your own domain - no external request, no layout shift, and better privacy:

jsx
// app/layout.js import { Inter } from 'next/font/google'; const inter = Inter({ subsets: ['latin'], display: 'swap' }); export default function RootLayout({ children }) { return ( <html lang='en' className={inter.className}> <body>{children}</body> </html> ); }

The font is self-hosted automatically and a matching fallback is size-adjusted to minimize shift while it loads. For custom font files, use next/font/local:

jsx
import localFont from 'next/font/local'; const brand = localFont({ src: './brand.woff2' });

You can also expose fonts as CSS variables (variable: '--font-inter') and reference them from Tailwind or CSS Modules.

Measuring the Impact

Run a Lighthouse audit before and after adopting these components on an image-heavy page. Largest Contentful Paint and Cumulative Layout Shift typically improve immediately - these are the metrics Google uses in ranking, which is why this lesson matters for more than aesthetics.

Key Takeaways

  • next/image resizes, converts, and lazy-loads images, and prevents layout shift.
  • Statically imported images get dimensions automatically; remote images need width, height, and remotePatterns config.
  • Use priority for above-the-fold heroes and sizes with fill for responsive images.
  • next/font self-hosts Google or local fonts with zero layout shift and no external requests.

Next up: Lesson 12 goes deeper into search visibility with the Metadata API and SEO best practices.

Image and Font Optimization - Next.js | CodeYourCraft | CodeYourCraft