<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged image-optimization</title>
<link>https://coderlegion.com/tag/image-optimization</link>
<description>Powered by Question2Answer</description>
<item>
<title>Image Optimization in Next.js 16: The Complete 2026 Guide</title>
<link>https://coderlegion.com/24490/image-optimization-in-next-js-16-the-complete-2026-guide</link>
<description>&lt;p&gt;If you've ever shipped a page with a 2.5MB hero image and watched your Lighthouse score crash to single digits, you already know why this matters. A slow, unoptimized image is one of the fastest ways to lose a visitor — most people won't wait more than a couple of seconds for a page to feel usable, and a giant JPEG sitting above the fold is usually the culprit.&lt;/p&gt;
&lt;p&gt;The good news: Next.js has had a built-in fix for this since version 10, and Next.js 16 makes it stricter, safer, and a little different from what you might remember. If you've been using &lt;code&gt;priority&lt;/code&gt; or skipping &lt;code&gt;qualities&lt;/code&gt; config, some of that has changed.&lt;/p&gt;
&lt;p&gt;By the end of this guide, you'll know exactly how the &lt;code&gt;next/image&lt;/code&gt; component works in Next.js 16, how to configure it correctly for local and remote images, and how to avoid the security-related gotchas that were added in this version.&lt;/p&gt;
&lt;h3 id=&quot;-lt-img-gt-vs-next-image-at-a-glance&quot;&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; vs &lt;code&gt;next/image&lt;/code&gt; at a Glance&lt;/h3&gt;
&lt;p&gt;Before diving in, here's what you actually get by switching:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Feature &lt;/th&gt;&lt;th&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; &lt;/th&gt;&lt;th&gt;&lt;code&gt;next/image&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Automatic resizing per device &lt;/td&gt;&lt;td&gt;❌ Manual &lt;/td&gt;&lt;td&gt;✅ Automatic&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Format conversion (WebP/AVIF) &lt;/td&gt;&lt;td&gt;❌ Manual &lt;/td&gt;&lt;td&gt;✅ Automatic&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Lazy loading &lt;/td&gt;&lt;td&gt;⚠️ Basic (&lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; only) &lt;/td&gt;&lt;td&gt;✅ Built-in, smarter defaults&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Layout shift (CLS) prevention &lt;/td&gt;&lt;td&gt;❌ Manual &lt;/td&gt;&lt;td&gt;✅ Enforced via &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Responsive &lt;code&gt;srcset&lt;/code&gt; generation &lt;/td&gt;&lt;td&gt;❌ Manual &lt;/td&gt;&lt;td&gt;✅ Automatic&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Blur-up placeholder &lt;/td&gt;&lt;td&gt;❌ Manual &lt;/td&gt;&lt;td&gt;✅ Built-in for local images&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Caching of optimized variants &lt;/td&gt;&lt;td&gt;❌ None &lt;/td&gt;&lt;td&gt;✅ Disk cache with configurable TTL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Remote source security &lt;/td&gt;&lt;td&gt;❌ None &lt;/td&gt;&lt;td&gt;✅ &lt;code&gt;remotePatterns&lt;/code&gt; allowlist&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That table alone is the reason &lt;code&gt;next/image&lt;/code&gt; exists — everything on the right side would otherwise be work you'd have to build and maintain yourself.&lt;/p&gt;
&lt;h3 id=&quot;why-image-optimization-is-tricky&quot;&gt;Why Image Optimization Is Tricky&lt;/h3&gt;
&lt;p&gt;Browsers don't know how big your users' screens are ahead of time. Serve one giant image and you're wasting bandwidth on mobile. Serve a tiny one and desktop users get blurry visuals. On top of that, modern formats like WebP and AVIF can shrink file sizes by 30–70% compared to JPEG/PNG — but only if you actually generate and serve them.&lt;/p&gt;
&lt;p&gt;Doing all of this by hand (multiple sizes, multiple formats, lazy loading, layout shift prevention) is a lot of manual work. The &lt;code&gt;next/image&lt;/code&gt; component automates it: one component, and Next.js generates the right size, right format, and right loading behavior automatically.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Every layout-shift issue you've seen from images loading in late is what the &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; requirement on &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; is designed to prevent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;This guide assumes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js 16&lt;/strong&gt; with the App Router&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypeScript&lt;/strong&gt; (strict mode)&lt;/li&gt;
&lt;li&gt;Basic familiarity with React components&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're on an older version, run the upgrade codemod first:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx @next/codemod@canary upgrade latest
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-1-replace-lt-img-gt-with-next-image&quot;&gt;Step 1: Replace &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with &lt;code&gt;next/image&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Instead of a plain &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, import &lt;code&gt;Image&lt;/code&gt; from &lt;code&gt;next/image&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// app/page.tsx
import Image from 'next/image'

export default function Page() {
  return (
    &amp;lt;Image
      src=&quot;/profile.png&quot;
      width={500}
      height={500}
      alt=&quot;Picture of the author&quot;
    /&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;src&lt;/code&gt; points to a file in your &lt;code&gt;public/&lt;/code&gt; folder. &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; are the image's &lt;em&gt;intrinsic&lt;/em&gt; dimensions (in pixels) — not the size it renders at on screen. Next.js uses these to calculate the aspect ratio and reserve space in the layout before the image finishes loading, which prevents the page from jumping around (this jumping is called &lt;strong&gt;Cumulative Layout Shift&lt;/strong&gt;, or CLS — a metric Google uses to judge page experience).&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Beginners often skip &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; because &quot;the image already has a size.&quot; Next.js still needs these numbers explicitly, unless you use a static import or the &lt;code&gt;fill&lt;/code&gt; prop (both covered below).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-2-local-vs-static-imports&quot;&gt;Step 2: Local vs. Static Imports&lt;/h3&gt;
&lt;p&gt;There are two ways to reference a local image, and they behave differently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option A — string path&lt;/strong&gt; (you provide width/height manually):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Image src=&quot;/hero.jpg&quot; width={1200} height={600} alt=&quot;Hero banner&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Option B — static import&lt;/strong&gt; (Next.js infers width/height automatically):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// app/page.tsx
import Image from 'next/image'
import hero from '../public/hero.jpg'

export default function Page() {
  return &amp;lt;Image src={hero} alt=&quot;Hero banner&quot; /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; With a static import, Next.js reads the file at build time, figures out its real dimensions, and even auto-generates a small blurred placeholder (&lt;code&gt;blurDataURL&lt;/code&gt;) for JPG, PNG, WebP, or AVIF files — with zero extra config. This is the easiest and safest way to handle local images.&lt;/p&gt;
&lt;h3 id=&quot;step-3-configure-remote-images-with-remotepatterns&quot;&gt;Step 3: Configure Remote Images with &lt;code&gt;remotePatterns&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If your image comes from an external URL (a CMS, S3 bucket, CDN), Next.js won't optimize it by default — for security reasons, you have to explicitly allow it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'assets.example.com',
        pathname: '/uploads/**',
      },
    ],
  },
}

export default nextConfig
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// app/page.tsx
&amp;lt;Image
  src=&quot;https://assets.example.com/uploads/profile.png&quot;
  alt=&quot;Picture of the author&quot;
  width={500}
  height={500}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;remotePatterns&lt;/code&gt; is a strict allowlist. Any external image URL that doesn't match one of these patterns gets rejected with a &lt;code&gt;400 Bad Request&lt;/code&gt;. Since remote images aren't available at build time, you must supply &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; manually — Next.js can't inspect a file it doesn't have locally.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Don't leave &lt;code&gt;remotePatterns&lt;/code&gt; wide open (e.g. matching &lt;code&gt;**&lt;/code&gt; with no protocol or pathname) — that lets anyone route arbitrary external URLs through your server's image optimizer. Be as specific as possible with &lt;code&gt;hostname&lt;/code&gt; and &lt;code&gt;pathname&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; If your &lt;code&gt;src&lt;/code&gt; image requires authentication (a private bucket, a signed CMS endpoint), the default loader won't work — for security reasons, Next.js does not forward headers when fetching the source image. In that case, set the &lt;code&gt;unoptimized&lt;/code&gt; prop on that image instead of trying to pass auth headers through.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-4-responsive-images-with-sizes&quot;&gt;Step 4: Responsive Images with &lt;code&gt;sizes&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;By default, if you don't tell Next.js how wide the image will actually render, it assumes it could be as wide as the entire viewport — and generates a larger &lt;code&gt;srcset&lt;/code&gt; than necessary.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Image
  src=&quot;/banner.jpg&quot;
  alt=&quot;Banner&quot;
  fill
  sizes=&quot;(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;sizes&lt;/code&gt; tells the browser: &quot;on small screens, this image is roughly full width; on medium screens, half width; otherwise a third of the width.&quot; The browser then picks the most appropriately sized file from the generated &lt;code&gt;srcset&lt;/code&gt; instead of always downloading the largest version.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;sizes&lt;/code&gt; whenever:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You're using the &lt;code&gt;fill&lt;/code&gt; prop, or&lt;/li&gt;
&lt;li&gt;The image is styled to be responsive via CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-5-fill-for-unknown-dimensions&quot;&gt;Step 5: &lt;code&gt;fill&lt;/code&gt; for Unknown Dimensions&lt;/h3&gt;
&lt;p&gt;Sometimes you don't know an image's dimensions ahead of time — a user-uploaded avatar, for example.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;div style={{ position: 'relative', width: '400px', height: '300px' }}&amp;gt;
  &amp;lt;Image
    src=&quot;/uploaded-photo.jpg&quot;
    alt=&quot;User upload&quot;
    fill
    sizes=&quot;400px&quot;
    style={{ objectFit: 'cover' }}
  /&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;fill&lt;/code&gt; makes the image expand to match its parent container, so the parent &lt;strong&gt;must&lt;/strong&gt; have &lt;code&gt;position: relative&lt;/code&gt;, &lt;code&gt;absolute&lt;/code&gt;, or &lt;code&gt;fixed&lt;/code&gt;. &lt;code&gt;objectFit: 'cover'&lt;/code&gt; crops the image to fill the container without distorting it — similar to CSS &lt;code&gt;background-size: cover&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-6-choose-the-right-loading-strategy&quot;&gt;Step 6: Choose the Right Loading Strategy&lt;/h3&gt;
&lt;p&gt;Not every image on a page deserves the same treatment. Next.js gives you four levers, and picking the right one per image matters more than most beginners realize.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Strategy &lt;/th&gt;&lt;th&gt;How to set it &lt;/th&gt;&lt;th&gt;When to use it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Lazy (default)&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Nothing — &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; is automatic &lt;/td&gt;&lt;td&gt;Any image below the fold: galleries, article body images, footer content&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Eager&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;loading=&quot;eager&quot;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;An above-the-fold image you want loaded immediately, without waiting for scroll distance to trigger it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;High fetch priority&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Your actual LCP candidate in most cases — this is what Next.js itself recommends reaching for first&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Preload&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;preload&lt;/code&gt; &lt;/td&gt;&lt;td&gt;A narrower case: you specifically want the browser to start fetching the image from the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, before it's even discovered in the HTML body — and you're certain only one image qualifies&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// Below the fold — do nothing, lazy is default
&amp;lt;Image src=&quot;/gallery-1.jpg&quot; width={400} height={300} alt=&quot;Gallery photo&quot; /&amp;gt;

// Above the fold but not the LCP element — load immediately, don't wait for lazy trigger
&amp;lt;Image src=&quot;/secondary-banner.jpg&quot; width={800} height={300} alt=&quot;Banner&quot; loading=&quot;eager&quot; /&amp;gt;

// The confirmed LCP element — Next's own recommendation for most cases
&amp;lt;Image src=&quot;/hero.jpg&quot; width={1200} height={600} alt=&quot;Hero&quot; fetchPriority=&quot;high&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; Lazy loading defers off-screen images until the browser gets close to them, saving bandwidth on page load. Eager loading forces an image to load immediately regardless of position — useful just below the fold. &lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt; bumps an image's priority in the browser's normal fetch queue without the stricter constraints of &lt;code&gt;preload&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Correction worth noting:&lt;/strong&gt; It's tempting to reach for &lt;code&gt;preload&lt;/code&gt; as the default &quot;make my hero load fast&quot; fix, but Next.js's own docs say the opposite: &lt;em&gt;&quot;In most cases, you should use &lt;code&gt;loading='eager'&lt;/code&gt; or &lt;code&gt;fetchPriority='high'&lt;/code&gt; instead of &lt;code&gt;preload&lt;/code&gt;.&quot;&lt;/em&gt; Reserve &lt;code&gt;preload&lt;/code&gt; for cases where you're certain exactly one image is the LCP element and you specifically need the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; preload behavior — and never combine it with &lt;code&gt;loading&lt;/code&gt; or &lt;code&gt;fetchPriority&lt;/code&gt; on the same image, since Next.js explicitly warns against that combination.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Real example from the docs:&lt;/strong&gt; If you're swapping images based on light/dark theme (two &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; components, one hidden via CSS), you can't use &lt;code&gt;preload&lt;/code&gt; or &lt;code&gt;loading=&quot;eager&quot;&lt;/code&gt; on either one — both would end up loading. &lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt; is the only safe option there, since it doesn't force an eager fetch the way the other two do.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-7-controlling-quality-qualities-is-now-required-config&quot;&gt;Step 7: Controlling Quality — &lt;code&gt;qualities&lt;/code&gt; Is Now Required Config&lt;/h3&gt;
&lt;p&gt;Another Next.js 16 change: the &lt;code&gt;qualities&lt;/code&gt; array in &lt;code&gt;next.config.ts&lt;/code&gt; is now &lt;strong&gt;required&lt;/strong&gt; if you want to use any quality value other than the default.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// next.config.ts
const nextConfig: NextConfig = {
  images: {
    qualities: [25, 50, 75, 100],
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Image src=&quot;/photo.jpg&quot; width={800} height={600} alt=&quot;Photo&quot; quality={90} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; Previously, you could pass any &lt;code&gt;quality&lt;/code&gt; value (1–100) freely. Starting in Next.js 16, the value you pass to &lt;code&gt;quality&lt;/code&gt; must match one of the values listed in &lt;code&gt;qualities&lt;/code&gt; in your config — otherwise Next.js snaps to the closest allowed value. This exists because unrestricted quality values could be abused to generate an unlimited number of cached image variants, wasting server resources.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; If you don't configure &lt;code&gt;qualities&lt;/code&gt; at all, the default allowed value is &lt;code&gt;[75]&lt;/code&gt; — meaning &lt;code&gt;quality={90}&lt;/code&gt; would silently be clamped down to 75.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-8-choosing-output-formats-avif-vs-webp&quot;&gt;Step 8: Choosing Output Formats — AVIF vs. WebP&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// next.config.ts
const nextConfig: NextConfig = {
  images: {
    formats: ['image/avif', 'image/webp'],
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; Next.js checks the browser's &lt;code&gt;Accept&lt;/code&gt; header and serves whichever format is listed first in your array that the browser supports. AVIF compresses roughly 20% smaller than WebP but takes about 50% longer to encode on first request (subsequent requests are cached, so this only affects the very first visitor per image size/format combination). For most projects, WebP alone is a solid, faster-to-generate default — add AVIF if you want to squeeze out extra savings on high-traffic pages.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Enabling both formats doubles your optimized-image storage, since Next.js caches AVIF and WebP versions separately. Keep an eye on &lt;code&gt;maximumDiskCacheSize&lt;/code&gt; if disk space is a concern.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-9-blur-placeholders-for-a-smoother-load&quot;&gt;Step 9: Blur Placeholders for a Smoother Load&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Image
  src=&quot;/photo.jpg&quot;
  alt=&quot;Photo&quot;
  width={800}
  height={600}
  placeholder=&quot;blur&quot;
  blurDataURL=&quot;data:image/jpeg;base64,/9j/4AAQSk...&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;placeholder=&quot;blur&quot;&lt;/code&gt; shows a blurred, low-res version of the image while the full one loads, which feels smoother than a blank space. For statically imported local images, Next.js generates &lt;code&gt;blurDataURL&lt;/code&gt; for you automatically. For remote or dynamic images, you need to generate a small base64 placeholder yourself (a tool like Plaiceholder can do this).&lt;/p&gt;
&lt;h3 id=&quot;step-10-svgs-and-skipping-optimization&quot;&gt;Step 10: SVGs and Skipping Optimization&lt;/h3&gt;
&lt;p&gt;SVGs are vector graphics — resizing them losslessly means there's nothing for the optimizer to do. Next.js skips optimizing them by default and recommends the &lt;code&gt;unoptimized&lt;/code&gt; prop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Image src=&quot;/logo.svg&quot; width={120} height={40} alt=&quot;Logo&quot; unoptimized /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;unoptimized&lt;/code&gt; tells Next.js to serve the file exactly as-is, skipping resizing, format conversion, and quality adjustment. This also applies to tiny images (under 1KB) and animated GIFs, where optimization overhead outweighs any benefit.&lt;/p&gt;
&lt;h3 id=&quot;step-11-preserving-seo-rankings-with-overridesrc&quot;&gt;Step 11: Preserving SEO Rankings with &lt;code&gt;overrideSrc&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;By default, &lt;code&gt;next/image&lt;/code&gt; rewrites the rendered &lt;code&gt;src&lt;/code&gt; attribute to point at Next's optimization endpoint (&lt;code&gt;/_next/image?url=...&lt;/code&gt;) instead of the original file path. For a brand-new site that's irrelevant — but if you're migrating an already-live, already-indexed site from &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt;, it's worth knowing this changes the URL search engines see for that image.&lt;/p&gt;
&lt;p&gt;To be precise about what this does and doesn't mean: changing an image's URL doesn't erase or &quot;reset&quot; its rankings — search engines are perfectly capable of discovering and reindexing a new URL on their own, and image search visibility isn't tied to the URL string itself. What it &lt;em&gt;does&lt;/em&gt; mean is a gap while the new URL gets recrawled and reindexed, and any direct backlinks or bookmarks pointing at the old file path stop resolving to the same indexed result unless you redirect them. For a high-traffic image ranking well in image search, that gap is often reason enough to avoid it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Image
  src=&quot;/uploads/dental-clinic-hero.jpg&quot;
  overrideSrc=&quot;/uploads/dental-clinic-hero.jpg&quot;
  width={1200}
  height={600}
  alt=&quot;Modern dental clinic reception area&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; Next.js still generates the optimized &lt;code&gt;srcset&lt;/code&gt; behind the scenes, but &lt;code&gt;overrideSrc&lt;/code&gt; forces the final &lt;code&gt;src&lt;/code&gt; attribute in the rendered HTML to stay exactly what you specify — so the URL search engines already have indexed doesn't change, and there's no recrawl gap to wait out. Users still get the responsive, optimized images either way.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; This is mainly worth reaching for on pages that already get meaningful image search traffic. For most other migrations, letting the URL change and get reindexed naturally is completely fine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-12-custom-markup-with-getimageprops-&quot;&gt;Step 12: Custom Markup with &lt;code&gt;getImageProps()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes you don't want Next.js to render the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag for you — maybe you need a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element for art direction, or want to set a CSS background image using an optimized source. &lt;code&gt;getImageProps()&lt;/code&gt; gives you the computed props without rendering anything.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// app/components/theme-image.tsx
import { getImageProps } from 'next/image'

const { props } = getImageProps({
  src: '/mountain.jpg',
  alt: 'A scenic mountain view',
  width: 1200,
  height: 800,
})

function ImageWithCaption() {
  return (
    &amp;lt;figure&amp;gt;
      &amp;lt;img {...props} /&amp;gt;
      &amp;lt;figcaption&amp;gt;A scenic mountain view&amp;lt;/figcaption&amp;gt;
    &amp;lt;/figure&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;getImageProps()&lt;/code&gt; runs the same logic &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; uses internally — generating &lt;code&gt;srcset&lt;/code&gt;, &lt;code&gt;src&lt;/code&gt;, and sizing — and just hands you the resulting props object instead of a component. This is the tool to reach for with &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; elements, CSS &lt;code&gt;image-set()&lt;/code&gt; backgrounds, or any case where you need full control over the rendered markup while still getting optimized URLs.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; &lt;code&gt;getImageProps()&lt;/code&gt; can't be combined with the &lt;code&gt;placeholder&lt;/code&gt; prop, since there's no component lifecycle to remove the placeholder once the image loads.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;advanced-configuration&quot;&gt;Advanced Configuration&lt;/h3&gt;
&lt;p&gt;The following options aren't things you'll touch on day one, but they're worth knowing about once your app is live and you run into a specific problem.&lt;/p&gt;
&lt;h4 id=&quot;custom-image-loaders-skipping-next-s-built-in-optimizer-&quot;&gt;Custom Image Loaders (Skipping Next's Built-In Optimizer)&lt;/h4&gt;
&lt;p&gt;If you're already using a CDN that does its own image optimization — Cloudinary, Imgix, a headless CMS's built-in image API — you don't need Next.js to optimize on top of it. A &lt;code&gt;loader&lt;/code&gt; function builds the URL yourself instead of using Next's &lt;code&gt;/_next/image&lt;/code&gt; endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// lib/cloudinary-loader.ts
export default function cloudinaryLoader({ src, width, quality }: { src: string; width: number; quality?: number }) {
  return `https://res.cloudinary.com/demo/image/upload/w_${width},q_${quality || 75}/${src}`
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// next.config.ts
const nextConfig: NextConfig = {
  images: {
    loader: 'custom',
    loaderFile: './lib/cloudinary-loader.ts',
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;loaderFile&lt;/code&gt; applies this URL-building function to every &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; in the project, so you don't need to configure &lt;code&gt;remotePatterns&lt;/code&gt; or lean on Next's own optimizer at all — the CDN handles resizing and format conversion on its end.&lt;/p&gt;
&lt;h4 id=&quot;caching-behavior-with-minimumcachettl&quot;&gt;Caching Behavior with &lt;code&gt;minimumCacheTTL&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Optimized images are cached on disk with a default TTL of 4 hours (&lt;code&gt;minimumCacheTTL&lt;/code&gt; in &lt;code&gt;next.config.ts&lt;/code&gt;). If you've replaced an image file but the old version is still showing, this is usually why — the actual expiry used is whichever is larger: &lt;code&gt;minimumCacheTTL&lt;/code&gt; or the upstream image's own &lt;code&gt;Cache-Control&lt;/code&gt; header. There's no built-in way to manually invalidate a specific cached image, so keeping this value low is safer if your images change often.&lt;/p&gt;
&lt;h4 id=&quot;self-hosting-behind-a-proxy-or-cdn&quot;&gt;Self-Hosting Behind a Proxy or CDN&lt;/h4&gt;
&lt;p&gt;If you self-host Next.js behind your own reverse proxy or CDN, AVIF/WebP format negotiation can silently stop working — Next.js decides which format to serve based on the request's &lt;code&gt;Accept&lt;/code&gt; header, and if your proxy doesn't forward that header through, every browser ends up getting the original format regardless of what it actually supports. Worth checking if you notice &lt;code&gt;formats&lt;/code&gt; config seemingly having no effect in production.&lt;/p&gt;
&lt;h3 id=&quot;real-world-example-a-blog-post-page&quot;&gt;Real-World Example: A Blog Post Page&lt;/h3&gt;
&lt;p&gt;Here's how several of these pieces come together on an actual page — a blog post with one hero image (the LCP element) and a few inline body images that can load lazily.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// app/blog/[slug]/page.tsx
import Image from 'next/image'
import heroImage from '../../../public/blog/hero.jpg'

export default function BlogPost() {
  return (
    &amp;lt;article&amp;gt;
        {/* Hero — above the fold
            Uses a static import
            Automatically gets blurDataURL
            Marked as high priority
        */}

      &amp;lt;Image
        src={heroImage}
        alt=&quot;Team collaborating around a whiteboard&quot;
        sizes=&quot;100vw&quot;
        fetchPriority=&quot;high&quot;
        style={{ width: '100%', height: 'auto' }}
      /&amp;gt;

      &amp;lt;h1&amp;gt;How We Scaled Our Front-End Team&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;Some intro text about the article...&amp;lt;/p&amp;gt;

        {/* Inline content images
            Lazy-loaded by default
            Remote URLs
            Need remotePatterns
        */}

      &amp;lt;Image
        src=&quot;https://assets.devstacked.tech/blog/diagram-1.png&quot;
        alt=&quot;Team structure diagram&quot;
        width={800}
        height={450}
        sizes=&quot;(max-width: 768px) 100vw, 800px&quot;
      /&amp;gt;

      &amp;lt;p&amp;gt;More article content...&amp;lt;/p&amp;gt;

      {/* Another inline image, further down */}
      &amp;lt;Image
        src=&quot;https://assets.devstacked.tech/blog/screenshot-1.png&quot;
        alt=&quot;Dashboard screenshot&quot;
        width={800}
        height={500}
        sizes=&quot;(max-width: 768px) 100vw, 800px&quot;
      /&amp;gt;
    &amp;lt;/article&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; Only the hero gets &lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt;, since it's the confirmed LCP element — following Next's own guidance to reach for &lt;code&gt;fetchPriority&lt;/code&gt; over &lt;code&gt;preload&lt;/code&gt; in the common case. The static import means Next.js already knows its dimensions and generates a blur placeholder automatically. The two inline images come from a remote CMS bucket (so they'd need a matching &lt;code&gt;remotePatterns&lt;/code&gt; entry in &lt;code&gt;next.config.ts&lt;/code&gt;), have manually supplied &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt;, and are left with the default lazy loading since they're further down the page — no &lt;code&gt;fetchPriority&lt;/code&gt;, no &lt;code&gt;eager&lt;/code&gt;, just sensible defaults.&lt;/p&gt;
&lt;h3 id=&quot;image-optimization-checklist&quot;&gt;Image Optimization Checklist&lt;/h3&gt;
&lt;p&gt;Run through this before shipping a page with images:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Every &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag replaced with &lt;code&gt;next/image&lt;/code&gt;, or a documented reason why not (e.g. a tiny inline icon)&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; set on every image, or a static import / &lt;code&gt;fill&lt;/code&gt; used instead&lt;/li&gt;
&lt;li&gt;[ ] External image domains added to &lt;code&gt;remotePatterns&lt;/code&gt; — as narrow as possible, not wildcarded&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;sizes&lt;/code&gt; set on any image using &lt;code&gt;fill&lt;/code&gt; or styled to be responsive&lt;/li&gt;
&lt;li&gt;[ ] LCP image marked with &lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt; (Next's preferred approach), with &lt;code&gt;preload&lt;/code&gt; reserved for the narrower case where you need &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;-level preloading and are certain only one image qualifies&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;qualities&lt;/code&gt; configured in &lt;code&gt;next.config.ts&lt;/code&gt; if you use any &lt;code&gt;quality&lt;/code&gt; value besides 75&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;formats&lt;/code&gt; set to &lt;code&gt;['image/webp']&lt;/code&gt; at minimum; add AVIF only if the extra storage/encoding cost is worth it for your traffic&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;alt&lt;/code&gt; text is descriptive and meaningful for every image (empty string only for purely decorative images)&lt;/li&gt;
&lt;li&gt;[ ] SVGs and tiny/animated images marked &lt;code&gt;unoptimized&lt;/code&gt; instead of routed through the optimizer&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;blurDataURL&lt;/code&gt; provided for remote/dynamic images where a blur placeholder is used&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;overrideSrc&lt;/code&gt; considered for high-traffic, already-indexed images where you want to skip the recrawl gap entirely&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;frequently-asked-questions&quot;&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;h4 id=&quot;do-i-still-need-to-use-the-priority-prop-&quot;&gt;Do I still need to use the &lt;code&gt;priority&lt;/code&gt; prop?&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;priority&lt;/code&gt; still technically works but is deprecated as of Next.js 16. That said, don't just swap it 1:1 for &lt;code&gt;preload&lt;/code&gt; — Next.js recommends &lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt; (or &lt;code&gt;loading=&quot;eager&quot;&lt;/code&gt;) for most LCP images, and reserves &lt;code&gt;preload&lt;/code&gt; for narrower cases. See Step 6 for the breakdown.&lt;/p&gt;
&lt;h4 id=&quot;should-i-use-preload-for-my-hero-lcp-image-&quot;&gt;Should I use &lt;code&gt;preload&lt;/code&gt; for my hero/LCP image?&lt;/h4&gt;
&lt;p&gt;Usually not directly — Next's own docs say to use &lt;code&gt;loading=&quot;eager&quot;&lt;/code&gt; or &lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt; in most cases instead. &lt;code&gt;preload&lt;/code&gt; is meant for a narrower situation: when you're certain exactly one image is the LCP element and specifically want it fetched from the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; before the rest of the page is parsed.&lt;/p&gt;
&lt;h4 id=&quot;how-do-i-keep-my-image-seo-rankings-when-migrating-from-lt-img-gt-to-next-image-&quot;&gt;How do I keep my image SEO rankings when migrating from &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; to &lt;code&gt;next/image&lt;/code&gt;?&lt;/h4&gt;
&lt;p&gt;Changing an image's URL doesn't reset or erase its rankings — search engines can rediscover and reindex a new URL fine on their own. What it does mean is a recrawl/reindex gap, and any existing backlinks pointing at the old file path won't resolve the same way. Use the &lt;code&gt;overrideSrc&lt;/code&gt; prop to keep the original file path as the rendered &lt;code&gt;src&lt;/code&gt; attribute (Next.js still serves the optimized &lt;code&gt;srcset&lt;/code&gt; behind the scenes) if you want to skip that gap entirely — mainly worth it for pages already getting real image search traffic.&lt;/p&gt;
&lt;h4 id=&quot;why-is-my-quality-prop-being-ignored-&quot;&gt;Why is my &lt;code&gt;quality&lt;/code&gt; prop being ignored?&lt;/h4&gt;
&lt;p&gt;As of Next.js 16, &lt;code&gt;quality&lt;/code&gt; values must match an entry in your &lt;code&gt;qualities&lt;/code&gt; array in &lt;code&gt;next.config.ts&lt;/code&gt;. If you haven't configured it, the only allowed value is 75, so anything else gets rounded to the nearest allowed value.&lt;/p&gt;
&lt;h4 id=&quot;can-i-use-next-image-with-images-from-an-external-cms-&quot;&gt;Can I use &lt;code&gt;next/image&lt;/code&gt; with images from an external CMS?&lt;/h4&gt;
&lt;p&gt;Yes, but you must add the CMS's domain to &lt;code&gt;remotePatterns&lt;/code&gt; in &lt;code&gt;next.config.ts&lt;/code&gt;, and you'll need to supply &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; manually since Next.js can't inspect a remote file at build time.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; If your CMS provides image dimensions in its API response, pass those directly instead of hardcoding fixed values.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;should-i-always-use-avif-for-the-best-compression-&quot;&gt;Should I always use AVIF for the best compression?&lt;/h4&gt;
&lt;p&gt;Not necessarily. AVIF gives smaller files but takes longer to encode on first request. For most sites, WebP alone (the default) is a good balance of speed and size — add AVIF if performance budgets are tight and you can absorb the extra caching cost.&lt;/p&gt;
&lt;h4 id=&quot;what-s-the-difference-between-width-height-and-the-actual-rendered-size-&quot;&gt;What's the difference between &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; and the actual rendered size?&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; only tell Next.js the image's intrinsic aspect ratio, used to prevent layout shift — they don't control how big the image appears on screen. Actual rendered size is controlled by CSS (&lt;code&gt;style&lt;/code&gt; or &lt;code&gt;className&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;That's the full picture of image optimization in Next.js 16: swap &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; for &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt;, lock down remote sources with &lt;code&gt;remotePatterns&lt;/code&gt;, allowlist your quality values with &lt;code&gt;qualities&lt;/code&gt;, and reach for &lt;code&gt;fetchPriority=&quot;high&quot;&lt;/code&gt; over &lt;code&gt;preload&lt;/code&gt; for your LCP image in most cases. These changes exist mostly to close security gaps from earlier versions, so if you're migrating an older project, &lt;code&gt;qualities&lt;/code&gt; and &lt;code&gt;remotePatterns&lt;/code&gt; are the two configuration changes developers most commonly encounter when migrating to Next.js 16 — with &lt;code&gt;overrideSrc&lt;/code&gt; worth a look too if you're migrating a page that already ranks in image search.&lt;/p&gt;
&lt;p&gt;Next up, it's worth pairing this with a proper &lt;strong&gt;Metadata API&lt;/strong&gt; setup for full page-level SEO, or diving into &lt;strong&gt;Cache Components&lt;/strong&gt; to control how those optimized images and pages get cached at the edge.&lt;/p&gt;
&lt;h3 id=&quot;continue-learning&quot;&gt;Continue Learning&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/technical-seo-checklist&quot;&gt;The Complete Technical SEO Checklist for Next.js Developers (2026 Guide)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/nextjs-16-metadata&quot;&gt;How to Add Metadata in Next.js 16 (2026 Beginner's Guide)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/nextjs-rendering-strategies-explained&quot;&gt;Next.js Rendering Strategies Explained: SSR, SSG, CSR, ISR &amp;amp; Cache Components (2026)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;free-seo-tools&quot;&gt;Free SEO Tools&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/tools/meta-tag-generator&quot;&gt;Meta Tag Generator for Next.js &amp;amp; HTML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/tools/json-ld-generator&quot;&gt;JSON-LD Generator for Next.js &amp;amp; HTML&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24490/image-optimization-in-next-js-16-the-complete-2026-guide</guid>
<pubDate>Wed, 12 Aug 2026 09:44:18 +0000</pubDate>
</item>
<item>
<title>Boosting Web Performance with Image Optimization Techniques</title>
<link>https://coderlegion.com/11668/boosting-web-performance-with-image-optimization-techniques</link>
<description>&lt;p&gt;Images can make or break a web application’s performance. A well-optimized image not only improves loading speed but also enhances user experience. Here are some effective techniques for optimizing images optimized for your audience's chill vibes.&lt;/p&gt;
&lt;h4 id=&quot;choosing-the-right-formats&quot;&gt;Choosing the Right Formats&lt;/h4&gt;
&lt;p&gt;Selecting the appropriate image format is crucial. Here’s a quick breakdown:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JPEG&lt;/strong&gt;: Ideal for photos and images with gradients. Great balance between quality and file size.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PNG&lt;/strong&gt;: Best for images needing transparency. Generally larger file sizes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SVG&lt;/strong&gt;: Perfect for logos and icons. Scalability without loss of quality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebP&lt;/strong&gt;: A modern format that provides superior compression without sacrificing quality. Consider using it for environments where it’s supported.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;real-world-example&quot;&gt;Real-World Example&lt;/h5&gt;
&lt;p&gt;Consider a photography portfolio. If images are in PNG format but could be JPEG, the file size may be unnecessarily large. Converting can save loading time significantly.&lt;/p&gt;
&lt;h4 id=&quot;compression-techniques&quot;&gt;Compression Techniques&lt;/h4&gt;
&lt;p&gt;Compressing images before uploading can dramatically reduce file sizes. Tools you can use include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://tinypng.com/&quot;&gt;TinyPNG&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;https://tinyjpg.com/&quot;&gt;TinyJPG&lt;/a&gt;&lt;/strong&gt;: Easy online tools for compressing JPEG and PNG files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ImageMagick&lt;/strong&gt;: A command-line tool effective for batch processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;practical-tip&quot;&gt;Practical Tip&lt;/h5&gt;
&lt;p&gt;When using &lt;a rel=&quot;nofollow&quot; href=&quot;https://tinypng.com/&quot;&gt;TinyPNG&lt;/a&gt;, I saw a 70% reduction in file size without noticeable quality loss on my images. Use compression settings that prioritize quality but don’t shy away from experimenting—every ounce of byte counts!&lt;/p&gt;
&lt;h4 id=&quot;implementing-lazy-loading&quot;&gt;Implementing Lazy Loading&lt;/h4&gt;
&lt;p&gt;Instead of loading all images at once, lazy loading ensures that images are only loaded as they come into the user’s viewport. This saves bandwidth and speeds up initial loading times.&lt;/p&gt;
&lt;h5 id=&quot;simple-implementation&quot;&gt;Simple Implementation&lt;/h5&gt;
&lt;p&gt;Many libraries can help with lazy loading, but a pure JavaScript function can do the trick:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const lazyImages = document.querySelectorAll('img[data-src]');

const lazyLoad = () =&amp;gt; {
  lazyImages.forEach(img =&amp;gt; {
    if (img.getBoundingClientRect().top &amp;lt; window.innerHeight) {
      img.src = img.dataset.src;
      img.classList.remove('lazy');
    }
  });
};

window.addEventListener('scroll', lazyLoad);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure your HTML images have a &lt;code&gt;data-src&lt;/code&gt; attribute where the actual image URL will be stored, and this function will load them when necessary.&lt;/p&gt;
&lt;h4 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h4&gt;
&lt;p&gt;Optimizing images is a balance between quality and performance. Selecting the right formats, compressing wisely, and implementing lazy loading can lead to a noticeably faster web experience. After applying these techniques, watch your bounce rates decrease and engagement soar. Go ahead and give it a try, you might be surprised by the results!&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/11668/boosting-web-performance-with-image-optimization-techniques</guid>
<pubDate>Sun, 15 Feb 2026 02:00:57 +0000</pubDate>
</item>
</channel>
</rss>