Images and Fonts
The idea in one sentence
Section titled “The idea in one sentence”next/image resizes, converts to modern formats, and lazy-loads your images while reserving their space, and next/font self-hosts your fonts at build time — so the page loads fast and never shifts.
next/image resizes, converts, and lazy-loads
Section titled “next/image resizes, converts, and lazy-loads”Image is a drop-in replacement for <img> that optimizes on demand. It generates a resized version per device, serves modern formats like WebP or AVIF when the browser supports them, and lazy-loads anything below the fold automatically.
When you import a local file, Next.js reads its intrinsic dimensions at build time, so width and height are filled in for you.
import Image from 'next/image'import hero from './hero.png'
export default function Page() { return <Image src={hero} alt="Product hero shot" />}width, height, and priority
Section titled “width, height, and priority”For any image whose size Next.js cannot infer — a remote URL, for example — you MUST pass width and height. They reserve the exact box before the pixels arrive, which is what prevents Cumulative Layout Shift. Add priority to the one image that is your Largest Contentful Paint so Next.js preloads it and skips lazy-loading.
// Remote image: width + height are required to reserve spaceimport Image from 'next/image'
export default function Avatar() { return ( <Image src="https://cdn.example.com/avatar.png" alt="User avatar" width={64} height={64} priority // preload the LCP image, skip lazy-loading /> )}When the dimensions are genuinely unknown, use fill inside a positioned parent and let CSS size the box instead.
// Unknown dimensions: use fill inside a positioned parent<div style={{ position: 'relative', width: 400, height: 300 }}> <Image src={src} alt="" fill sizes="400px" style={{ objectFit: 'cover' }} /></div>Remote images need remotePatterns
Section titled “Remote images need remotePatterns”Optimizing an arbitrary external URL would be an open proxy, so Next.js refuses unless you allowlist the host. Declare images.remotePatterns in next.config and be as specific as you can.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = { images: { remotePatterns: [ { protocol: 'https', hostname: 'cdn.example.com', pathname: '/**' }, ], },}
export default nextConfignext/font self-hosts at build time
Section titled “next/font self-hosts at build time”next/font downloads the font files at build time and serves them from your own origin. There is no runtime request to Google, and because the font metrics are known ahead of time it reserves the right space and produces zero layout shift.
// app/layout.tsx — self-hosted, zero layout shift, no request to Googleimport { Inter } from 'next/font/google'import localFont from 'next/font/local'
const inter = Inter({ subsets: ['latin'], display: 'swap' })const brand = localFont({ src: './brand.woff2' })
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en" className={inter.className}> <body className={brand.className}>{children}</body> </html> )}flowchart LR Src[Source asset] --> Build[Build step] Build --> Opt["Resized, WebP/AVIF, self-hosted font"] Opt --> Reserve["width + height reserve space"] Reserve --> Page["No layout shift, fast LCP"]