Back to Blog
Lesson 28 of the Next.js: Build Full-Stack Apps with the App Router course
Next.jsAugust 15, 20264 min read

Optimizing Images in Next.js: A Practical Guide to next/image

Learn to implement next/image to handle responsive assets and optimize your blog's performance. Master image dimensions and prevent layout shifts today.

Next.jsImage OptimizationPerformanceWeb DevelopmentFrontend
A man holding a mirror is visible through a digital camera's viewfinder, showcasing photography techniques.

Previously in this course, we explored using environment variables to secure our blog's configuration. In this lesson, we shift our focus to visual performance by mastering image optimization in Next.js.

Serving unoptimized, full-resolution images is a common way to tank your page load speeds and negatively impact your Core Web Vitals. The Next.js next/image component solves this by providing automatic resizing, format conversion (like WebP/AVIF), and lazy loading out of the box.

Why Use the Next.js Image Component?

Standard HTML <img> tags are "dumb"—they display whatever file you give them, regardless of the user's screen size or connection speed. If you upload a 5MB hero image, your mobile users pay the cost of downloading that entire file.

next/image acts as a wrapper around the native tag that adds:

  • Automatic Resizing: Serves smaller images for smaller screens.
  • Modern Formats: Automatically serves WebP or AVIF if the browser supports them.
  • Layout Stability: Enforces width/height to prevent Cumulative Layout Shift (CLS).
  • Lazy Loading: Only loads images as they approach the viewport.

While developers often look into complex image optimization pipelines for advanced use cases, the built-in component is the best place to start for any Next.js project.

Implementing next/image

Flat lay of wooden letter blocks spelling 'Next Steps', inspiring progress and motivation.

To use the component, import it from next/image. Let's update our PostCard component—created in our lesson on building reusable blog components—to use an optimized image instead of a standard <img> tag.

TSX
import Image from CE9178">'next/image';

export default function PostCard({ title, imageUrl }) {
  return (
    <div className="border rounded-lg overflow-hidden">
      <Image 
        src={imageUrl} 
        alt={CE9178">`Cover image for ${title}`} 
        width={800} 
        height={400} 
        className="object-cover"
        sizes="(max-width: 768px) 100vw, 800px"
      />
      <h2 className="p-4 text-xl font-bold">{title}</h2>
    </div>
  );
}

Key Props Explained

  1. width and height: These are required to calculate the aspect ratio and prevent the browser from "jumping" as the image loads.
  2. alt: Always include descriptive text to maintain accessibility standards.
  3. sizes: This tells the browser how wide the image will be at different breakpoints. It's critical for performance; without it, the browser assumes the image is full-width.
  4. className: You can use Tailwind utilities here just like you would with a regular image.

Handling Responsive Images

If you aren't sure of the exact dimensions, or if you want the image to fill its parent container, use the fill prop. When using fill, the parent element must have position: relative (or absolute/fixed).

TSX
<div className="relative w-full h-64">
  <Image 
    src="/hero.jpg" 
    alt="Hero" 
    fill 
    className="object-cover" 
  />
</div>

Practice Exercise: Optimize Your Blog Assets

  1. Locate your PostCard component in your running project.
  2. Replace the existing <img> tag with the next/image component.
  3. Ensure you have provided a width and height (or used fill with a positioned parent).
  4. Refresh your browser and inspect the image element. You should see that Next.js has automatically transformed the src into a call to its internal image optimization API.

Common Pitfalls

  • Missing Dimensions: If you don't provide width/height or fill, Next.js will throw an error in development. This is a safety feature to prevent layout shifts.
  • Large Unoptimized Assets: Even with next/image, don't upload 10MB source files. Use a tool to compress images before adding them to your project.
  • Incorrect sizes: If you specify sizes="100vw" for a thumbnail that only takes up 20% of the screen, the browser will download a much larger image than necessary, hurting performance.

FAQ

Q: Do I need to pay for image optimization? A: If you deploy to Vercel, image optimization is included in your platform usage. If you self-host, you might need to configure a custom loader or use a service like Cloudflare Image Resizing.

Q: Can I use external images? A: Yes, but you must define them in next.config.js under images.remotePatterns to prevent malicious image loading.

Q: How does this affect my Core Web Vitals? A: By providing proper dimensions and lazy loading, you significantly improve your Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS) scores, which moves the needle for web performance.

Recap

Team members presenting a project in a modern office setting with a focus on collaboration.

Next.js provides a powerful tool to handle asset delivery. By using next/image, you get automatic resizing, format selection, and layout protection. Always define your sizes prop correctly to ensure the browser fetches the most efficient image variant for the user's device.

Up next: We will prepare our application for the real world by learning how to deploy your project to Vercel.

Similar Posts