treeru.com

When you learn Next.js, you’re told to "always use <Image>." The official docs say the same. But while optimizing for PageSpeed, we discovered that a manually optimized <img> tag can produce higher scores in certain cases.

Understanding the difference between the two approaches lets you make the right choice for each situation.

Auto
<Image> approach
Manual
<img> approach
~0.3s
Hero LCP diff
Context
Right choice

1What Next.js Image Does Under the Hood

The next/image Image component automatically handles several things for you:

Auto Resize

Generates multiple srcset sizes from the original. Only the size matching the device width gets downloaded.

Format Conversion

Automatically converts to WebP if the browser supports it (AVIF requires separate config).

Lazy Loading by Default

Images outside the viewport are lazy-loaded automatically. Use the priority prop for hero images.

CLS Prevention

Requires width/height, preventing layout shift when images load.

Sounds great. But automation comes at a cost.

<!-- HTML generated by Next.js Image -->
<img
  alt="Hero Image"
  loading="lazy"
  width="900"
  height="1118"
  decoding="async"
  data-nimg="1"
  style="color:transparent"
  sizes="100vw"
  srcset="
    /_next/image?url=%2Fhero.webp&w=640&q=75 640w,
    /_next/image?url=%2Fhero.webp&w=750&q=75 750w,
    /_next/image?url=%2Fhero.webp&w=828&q=75 828w,
    /_next/image?url=%2Fhero.webp&w=1080&q=75 1080w,
    /_next/image?url=%2Fhero.webp&w=1200&q=75 1200w,
    /_next/image?url=%2Fhero.webp&w=1920&q=75 1920w,
    /_next/image?url=%2Fhero.webp&w=2048&q=75 2048w,
    /_next/image?url=%2Fhero.webp&w=3840&q=75 3840w
  "
  src="/_next/image?url=%2Fhero.webp&w=3840&q=75"
/>

Eight srcset entries per image. When every image generates this HTML, document size grows, and the browser needs time to calculate which size to download. The /_next/image endpoint also performs server-side resizing at runtime, making first requests slower.

2Manually Optimized img Tag

The alternative: optimize images yourself before they hit the server.

// Pre-convert at build time with sharp
// sharp input.png -resize 900 --avif quality=40 -o hero.avif

<!-- Clean, lightweight HTML -->
<img
  src="/images/hero.avif"
  alt="Hero Image"
  width={900}
  height={1118}
  fetchPriority="high"
  className="object-cover w-full h-full"
/>

Clean HTML. No srcset, no /_next/image endpoint. The image is already optimized in /public and served as a static file directly.

Manual Optimization Advantages

  • AVIF support: Next.js Image defaults to WebP. AVIF requires extra config, and runtime encoding is slow.
  • CDN cache hit rate: Static files are served directly from CDN. /_next/image must hit the server.
  • Precise quality control: Set the exact quality and dimensions for each image.
  • Build-time cost only: Convert once and you’re done. Zero runtime overhead.

3Head-to-Head Comparison

The same hero image loaded both ways:

Metric<Image><img> + AVIF
FormatWebP (auto)AVIF (manual)
File size~124KB~60KB
Serving methodServer resize then respondStatic file direct serve
First requestResize + encode waitInstant response
HTML size8 srcset entries (~500B)Single src (~80B)
Setup effortAlmost noneSharp script needed

The key difference is when image conversion happens. Image component converts at runtime (on user request); manual approach converts at build time. For hero images that always show the same content, build-time optimization is more efficient.

4When Image Component Wins

Image component isn’t bad—it shines when you can’t control the images.

User-uploaded images

Profile photos, post images — you don't know what size or format will be uploaded. Image auto-resizes.

CMS-sourced images

Images from external CMS can't be pre-optimized. Works seamlessly with remotePatterns.

Responsive art direction

When different devices need different image sizes, auto-generated srcset is convenient.

Hundreds of images

Blog thumbnails that change per post — manually converting each one with sharp isn't practical.

// User uploads — Image is the right choice
import Image from "next/image";

<Image
  src={user.profileImage}  // Size unknown
  alt={user.name}
  width={128}
  height={128}
  className="rounded-full object-cover"
/>

// CMS images — Image is the right choice
<Image
  src={post.thumbnailUrl}  // External URL
  alt={post.title}
  width={800}
  height={450}
  sizes="(max-width: 768px) 100vw, 50vw"
/>

5When Manual img Wins

When you have full control over the images, manual optimization delivers better results.

Hero images (LCP element)

Always the same image. Pre-convert to AVIF with fetchPriority='high' and preload for minimum LCP.

Background images, icons

Designer-provided assets with fixed size and format. Auto-resize adds no value.

Static site images

Company pages, service pages — images never change. Optimize once at build time, zero runtime cost.

PageSpeed-critical landing pages

When every 0.1s of LCP matters. Skip the server resize pipeline entirely.

// Hero image — img + AVIF is the right choice
<img
  src="/images/hero.avif"
  alt="Service overview"
  width={900}
  height={1118}
  fetchPriority="high"
  className="object-cover w-full h-full"
/>

// Service card — img + WebP + lazy
<img
  src="/images/service-ai.webp"
  alt="AI Service"
  width={1920}
  height={1434}
  loading="lazy"
  className="object-cover w-full h-full"
/>

Caveats When Using img

  • width/height required: Must be specified to prevent CLS. Image enforces this; img doesn’t.
  • Manual lazy loading: Image does it automatically; with img you must add loading="lazy" yourself.
  • You handle optimization: You need a build script with sharp or similar tools. More effort, but better results.

6Decision Framework

The rule is simple: "If you control the image, use img. If you don’t, use Image."

ScenarioRecommendedReason
Hero / LCP image<img> + AVIFSmallest size, instant serve, preloadable
Static assets (backgrounds, icons)<img> + WebPFixed size, no runtime cost needed
User uploads<Image>Unknown size, needs auto-resize
External CMS images<Image>remotePatterns handles external URLs
Hundreds of images (gallery)<Image>Manual optimization is impractical

Key Takeaways

Next.js Image optimizes for 'convenience'; manual img optimizes for 'performance'
Hero images (LCP elements) are faster with manual img + AVIF
User uploads, CMS content, and uncontrollable images are ideal for Image
When using img, manage width/height, loading='lazy', and fetchPriority yourself
You can mix both approaches in the same project — choose per situation

This comparison is based on Next.js 15. Image component behavior may vary by version. Actual performance differences depend on server environment, CDN configuration, and image sizes.

Need Help With Web Performance Optimization?

From image optimization to PageSpeed tuning, Treeru delivers measurable performance improvements for production websites.

Request Performance Consultation