# Next.js Optimization Performance optimization techniques for images, fonts, scripts, and bundles. ## Image Optimization ### Next.js Image Component Automatic optimization with modern formats (WebP, AVIF): ```tsx import Image from 'next/image' export default function Page() { return ( <> {/* Local image */} Hero image {/* Remote image */} Photo {/* Responsive fill */}
Background
{/* With blur placeholder */} Profile ) } ``` ### Image Props Reference **Required:** - `src` - Image path (string or static import) - `alt` - Alt text for accessibility - `width`, `height` - Dimensions (required unless using `fill`) **Optional:** - `fill` - Fill parent container (makes width/height optional) - `sizes` - Responsive sizes hint for srcset - `quality` - 1-100 (default 75) - `priority` - Disable lazy loading, preload image - `placeholder` - 'blur' | 'empty' (default 'empty') - `blurDataURL` - Data URL for blur placeholder - `loading` - 'lazy' | 'eager' (default 'lazy') - `style` - CSS styles - `className` - CSS class - `onLoad` - Callback when loaded ### Responsive Images with Sizes ```tsx Hero ``` This tells browser: - Mobile (<768px): Use 100% viewport width - Tablet (768-1200px): Use 50% viewport width - Desktop (>1200px): Use 33% viewport width ### Static Import for Local Images ```tsx import heroImage from '@/public/hero.jpg' Hero ``` ### Remote Image Configuration ```js // next.config.js module.exports = { images: { remotePatterns: [ { protocol: 'https', hostname: 'example.com', pathname: '/images/**', }, { protocol: 'https', hostname: 'cdn.example.com', } ], // Device sizes for srcset deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], // Image sizes for srcset imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // Supported formats formats: ['image/webp'], // Cache optimization images for 60 days minimumCacheTTL: 60 * 60 * 24 * 60, } } ``` ## Font Optimization ### Google Fonts Automatic optimization with zero layout shift: ```tsx // app/layout.tsx import { Inter, Roboto_Mono, Playfair_Display } from 'next/font/google' const inter = Inter({ subsets: ['latin'], display: 'swap', variable: '--font-inter', }) const robotoMono = Roboto_Mono({ subsets: ['latin'], display: 'swap', weight: ['400', '700'], variable: '--font-roboto-mono', }) const playfair = Playfair_Display({ subsets: ['latin'], display: 'swap', weight: ['400', '700', '900'], style: ['normal', 'italic'], }) export default function RootLayout({ children }) { return ( {children} ) } ``` Use CSS variables: ```css .code { font-family: var(--font-roboto-mono); } ``` ### Local Fonts ```tsx import localFont from 'next/font/local' const myFont = localFont({ src: [ { path: './fonts/my-font-regular.woff2', weight: '400', style: 'normal', }, { path: './fonts/my-font-bold.woff2', weight: '700', style: 'normal', } ], variable: '--font-my-font', display: 'swap', }) export default function RootLayout({ children }) { return ( {children} ) } ``` ### Font Display Strategies ```tsx const font = Inter({ display: 'swap', // Show fallback immediately, swap when loaded (recommended) // display: 'optional', // Only use font if available immediately // display: 'block', // Hide text until font loads (max 3s) // display: 'fallback', // Show fallback briefly, swap if loaded quickly // display: 'auto', // Browser default }) ``` ## Script Optimization ### Script Component Control loading behavior: ```tsx import Script from 'next/script' export default function Page() { return ( <> {/* Load after page is interactive (recommended for analytics) */} {/* With onLoad callback */}