Design wechseln

Next.js Bildoptimierung: Der vollständige Leitfaden zur Image-Komponente

Easton editorial illustration: performance inspection lens

Lighthouse-Score: 62 Punkte.

Zwei Wochen Arbeit in einem Next.js-Projekt – und die Performance-Bewertung gerade mal ausreichend. Unter Performance der größte Brocken: LCP (Largest Contentful Paint) bei 4,8 Sekunden, fast alles durch Bilder.

Damals war ich ratlos. Next.js sollte doch von Haus aus optimieren? Im Code: Hero-Bild auf der Startseite noch mit barem <img>, in der Shop-Liste Dutzende Produktbilder als 3–4-MB-Originale vom Server.

Erst später wurde klar: Next.js ist stark, aber Bildoptimierung braucht die Image-Komponente aktiv. Richtig eingesetzt, oft 60–80 % weniger Bildvolumen und LCP unter zwei Sekunden.

Viele scheitern trotzdem: Remote-Bilder mit „Un-configured Host“, springende Layouts, unübersichtliche Optionen. Dieser Artikel bündelt Stolpersteine und Lösungen – von null bis zur sauberen Next.js Image-Nutzung.

Warum die Next.js Image-Komponente?

Drei Fallen des normalen img-Tags

Ein <img src="xxx"> reicht doch? Beim Performance-Test zeigte sich das Gegenteil.

Erste Falle: kein Format-Tuning, verschwendete Bandbreite

Ein normales img lädt, was Sie liefern: 3-MB-PNG bleibt 3-MB. Moderne Browser unterstützen WebP (~30 % kleiner als JPEG) und AVIF (noch ~40 %). Das img-Tag wählt das nicht – es lädt nur die angegebene Datei.

Zweite Falle: eine Datei für alle Bildschirme

Besonders mobil: 2000×1500 hochgeladen, Viewport 375 px breit – trotzdem das Vollbild, vom Browser verkleinert. Langsam und teuer.

Dritte Falle: Layout-Verschiebung (CLS)

Seite lädt, Sie wollen klicken – ein Bild poppt rein, alles rutscht, falscher Klick. Das ist CLS (Cumulative Layout Shift), ein Core Web Vitals-Wert und SEO-Faktor.

Automatische Optimierung der Image-Komponente

Die Next.js Image-Komponente ist mehr als ein img-Wrapper – ein komplettes Optimierungspaket.

Automatische Formatauswahl

Anhand des Accept-Headers: AVIF wenn möglich, sonst WebP, sonst Original. Ohne Extra-Code.

Im Test: 500-KB-JPEG → WebP ~180 KB, AVIF ~120 KB. Bei vielen Bildern summiert sich das.

Responsive Loading

Je Viewport passende Varianten (srcset-Logik automatisch). Mobil ~375 px, Desktop ~1920 px – ohne manuelles srcset-Basteln.

Lazy Loading

Standard: nur Bilder im Viewport laden. Weniger Daten beim ersten Paint, schnellerer Start.

In der Praxis: 60–80 % weniger Bildvolumen, LCP unter 2,5 s, CLS nahe null – keine Theorie, sondern Messwerte aus echten Projekten.

Grundlagen: lokale vs. Remote-Bilder

Verwirrend am Anfang: manche Bilder funktionieren sofort, andere werfen Fehler. Unterschied: lokal vs. extern.

Lokale Bilder: der einfachste Fall

Dateien im Projekt – zwei gängige Wege.

Variante 1: import (empfohlen)

import heroImage from '/public/images/hero.jpg'
import Image from 'next/image'

export default function Home() {
  return (
    <Image
      src={heroImage}
      alt="Hero image"
    />
  )
}

Beim Build liest Next.js Breite und Höhe aus – oft ohne manuelles width/height. Für lokale Assets die bevorzugte Variante.

Variante 2: Pfad direkt

<Image
  src="/images/hero.jpg"
  width={1920}
  height={1080}
  alt="Hero image"
/>

Unter public/ mit Pfad – dann width und height Pflicht, sonst Fehler.

Remote-Bilder: die häufigste Stolperfalle

Externe URLs (z. B. Cloud Storage).

Typischer Fehler: „Un-configured Host“

<Image
  src="https://images.unsplash.com/photo-123456"
  width={800}
  height={600}
  alt="Sample image"
/>

Ohne Config meist:

Error: Invalid src prop (https://images.unsplash.com/photo-123456) on `next/image`, 
hostname "images.unsplash.com" is not configured under images in your `next.config.js`

Next.js will verhindern, dass beliebige URLs über Ihren Optimierungs-Endpunkt laufen. Erlaubte Hosts müssen explizit stehen.

Richtig: remotePatterns

In next.config.js (Next.js 14+ empfohlen):

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
        port: '',
        pathname: '/**',
      },
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
        port: '',
        pathname: '/my-bucket/**',
      },
    ],
  },
}

module.exports = nextConfig

Bedeutung:

  • protocol: https oder http
  • hostname: exakte Domain
  • port: meist leer
  • pathname: /** oder eingeschränkter Pfad

Nach Änderung: Dev-Server neu starten. Einmal Config geändert, Server nicht neu gestartet – halbe Stunde Debug umsonst.

Legacy: domains (nicht empfohlen)

module.exports = {
  images: {
    domains: ['images.unsplash.com', 's3.amazonaws.com'],
  },
}

In Next.js 14+ veraltet; remotePatterns ist sicherer (Pfad einschränkbar).

Warum width und height Pflicht sind

Außer per import müssen width und height gesetzt werden – gegen CLS.

Der Browser braucht Platzreservierung vor dem Download. Ohne Maße: Layout springt nach dem Laden.

Responsive Breite? Dafür gibt es fill (siehe unten).

Layout-Verschiebung (CLS) vermeiden

Springende Seiten nerven. Auf einer News-Site die häufigste Beschwerde: „Wollte den Titel klicken – Bild kam, Klick landete auf der Werbung.“

Was CLS ist und warum es zählt

CLS = kumulative Verschiebung während des Ladens. Google Core Web Vitals, SEO-relevant. Schlecht ab 0,1; gut darunter. Viele Bilder ohne Platzhalter → hoher CLS.

Wie Image CLS verhindert

Kern: Platz im Layout reservieren.

Mit width und height reserviert der Browser den Bereich vor dem Download – kein Sprung.

<Image
  src="/product.jpg"
  width={400}
  height={300}
  alt="Product image"
/>

400×300 Platzhalter, dann Bild – CLS oft null.

Bei fluidem Layout reicht feste Pixel nicht – dann fill.

Responsive: fill

Bild füllt den Parent; Größe per CSS.

<div style={{ position: 'relative', width: '100%', height: '400px' }}>
  <Image
    src="/hero.jpg"
    fill
    style={{ objectFit: 'cover' }}
    alt="Hero image"
  />
</div>

Wichtig:

  1. Parent: position: relative
  2. Parent: feste Höhe (nicht nur height: auto)
  3. objectFit: cover (füllen, ggf. crop) oder contain (ganzes Bild, evtl. Ränder)

Mit bekannter Parent-Höhe bleibt CLS kontrollierbar.

sizes: welche Auflösung laden?

Mit fill brauchen Sie sizes, sonst wählt Next.js die falsche Variante.

<div style={{ position: 'relative', width: '100%', height: '400px' }}>
  <Image
    src="/hero.jpg"
    fill
    sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
    style={{ objectFit: 'cover' }}
    alt="Hero image"
  />
</div>

Bedeutung:

  • ≤768 px: 100 % Viewport-Breite
  • 768–1200 px: 50 % Viewport
  • 1200 px: 33 % Viewport

Next.js erzeugt passende Varianten; das Gerät lädt die passende – weniger Daten, schneller.

Praxis: typische Layouts

Hero (volle Breite, Above-the-fold)

<div style={{ position: 'relative', width: '100%', height: '60vh' }}>
  <Image
    src="/hero.jpg"
    fill
    priority
    sizes="100vw"
    style={{ objectFit: 'cover' }}
    alt="Hero image"
  />
</div>

priority für sofortiges Laden; sizes="100vw" = volle Viewport-Breite.

Artikel-Thumbnail (fest)

<Image
  src={post.thumbnail}
  width={300}
  height={200}
  alt={post.title}
/>

Produktgitter (responsive)

<div style={{ position: 'relative', width: '100%', paddingBottom: '100%' }}>
  <Image
    src={product.image}
    fill
    sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
    style={{ objectFit: 'cover' }}
    alt={product.name}
  />
</div>

paddingBottom: '100%' = quadratischer 1:1-Container; mobil 1 Spalte, Tablet 2, Desktop 3.

Performance: zentrale Props

priority: kritische Above-the-fold-Bilder

Standard: Lazy Load. Hero und Logo sollen sofort kommen – sonst leerer Bereich.

<Image
  src="/hero.jpg"
  width={1920}
  height={1080}
  priority
  alt="Hero image"
/>

Mit priority: kein Lazy Load, preload im <head>, besserer LCP. Einmal Hero mit priority: LCP von 3,8 s auf 2,1 s.

Wann priority? Hero, großes Logo, Artikel-Header, alles was LCP sein kann.

Nicht auf alle 20 Bilder – parallele Downloads bremsen eher.

Next.js 16 (RC)

priority wird zu preload:

<Image
  src="/hero.jpg"
  width={1920}
  height={1080}
  preload
  alt="Hero image"
/>

Alternativ:

<Image
  src="/hero.jpg"
  width={1920}
  height={1080}
  loading="eager"
  fetchPriority="high"
  alt="Hero image"
/>

loading: Lade-Strategie

  • lazy (Default): erst im Viewport
  • eager: sofort

Meist reicht lazy; Above-the-fold mit eager oder priority.

// Unten auf der Seite – lazy (Default)
<Image src="/related-1.jpg" width={300} height={200} alt="Related post" />

// Hauptinhalt oben – eager
<Image src="/main-content.jpg" width={800} height={600} loading="eager" alt="Main content" />

quality: Qualität vs. Größe

1–100, Default 75.

<Image
  src="/product.jpg"
  width={800}
  height={600}
  quality={90}
  alt="Product image"
/>

Faustregeln:

  • Hero / wichtig: quality={90}
  • Standard: 75
  • Thumbnails / Hintergrund: 60

90 → 75: oft ~30 % kleiner, kaum sichtbar. 75 → 60: noch ~20 %, auf normalen Displays ok.

Next.js 16: quality kann Pflicht werden (Missbrauch über URL-Parameter). Beim Upgrade jedes Image mit quality versehen.

WebP vs. AVIF

Automatisch per Accept: AVIF > WebP > Original. AVIF ~30–40 % kleiner als WebP; Chrome 85+, Firefox 93+, Safari 16+.

Kombinierte Beispiele

Hero (priority, hohe Qualität)

<div style={{ position: 'relative', width: '100%', height: '60vh' }}>
  <Image
    src="/hero.jpg"
    fill
    priority
    quality={90}
    sizes="100vw"
    style={{ objectFit: 'cover' }}
    alt="Welcome to our site"
  />
</div>

Listen-Thumbnails

{posts.map(post => (
  <Image
    key={post.id}
    src={post.thumbnail}
    width={300}
    height={200}
    quality={75}
    alt={post.title}
  />
))}

Footer-Icons

<Image
  src="/footer-icon.png"
  width={40}
  height={40}
  quality={60}
  alt="Footer icon"
/>

Häufige Fehler und Fixes

Fehler 1: Un-configured Host

Error: Invalid src prop (https://example.com/image.jpg) on `next/image`, 
hostname "example.com" is not configured under images in your `next.config.js`

Ursache: externe URL ohne remotePatterns.

module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        port: '',
        pathname: '/**',
      },
    ],
  },
}

Hinweise: Dev-Server neu starten; hostname exakt, kein *.example.com; mehrere Hosts = mehrere Einträge.

Fehler 2: hoher CLS

Symptom: Inhalte springen beim Bildladen.

Ursachen: fehlende width/height, oder fill ohne Parent-Höhe.

// ❌
<Image src="/product.jpg" alt="Product" />

// ✅
<Image src="/product.jpg" width={400} height={300} alt="Product" />
// ❌ Parent ohne Höhe
<div style={{ position: 'relative', width: '100%' }}>
  <Image src="/hero.jpg" fill alt="Hero" />
</div>

// ✅
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
  <Image src="/hero.jpg" fill alt="Hero" />
</div>

Fehler 3: unscharf oder zu groß auf Mobile

Oft fehlendes sizes → Default 100vw, obwohl das Bild nur halb so breit ist.

<Image
  src="/product.jpg"
  width={400}
  height={300}
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
  alt="Product"
/>

Feste Thumbnail-Größe: nur width/height, kein sizes nötig.

Fehler 4: veraltete APIs

domains → remotePatterns (siehe oben).

onLoadingComplete → onLoad

// ❌
<Image
  src="/image.jpg"
  width={400}
  height={300}
  onLoadingComplete={() => console.log('loaded')}
  alt="Image"
/>

// ✅
<Image
  src="/image.jpg"
  width={400}
  height={300}
  onLoad={() => console.log('loaded')}
  alt="Image"
/>

Next.js 16: priority → preload (siehe oben).

Kurz-Checkliste

  1. Remote: remotePatterns?
  2. Config-Änderung: Server neu gestartet?
  3. width/height oder Parent-Höhe bei fill?
  4. fill: Parent relative + feste Höhe?
  5. Responsive: sinnvolles sizes?
  6. Keine veralteten APIs (domains, onLoadingComplete)?

Fortgeschritten: Best Practices

placeholder

blur (lokal per import)

import Image from 'next/image'
import heroImage from '/public/hero.jpg'

export default function Hero() {
  return (
    <Image
      src={heroImage}
      placeholder="blur"
      alt="Hero image"
    />
  )
}

Next.js erzeugt ein kleines Base64-Vorschaubild – bekannt von Instagram/Medium.

Remote mit blurDataURL

<Image
  src="https://example.com/image.jpg"
  width={800}
  height={600}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
  alt="Remote image"
/>

Tools wie blurred.dev oder sharp auf dem Server.

empty: explizit leerer Platzhalter (Default).

CDN / Custom Loader

// next.config.js
module.exports = {
  images: {
    loader: 'cloudinary',
    path: 'https://res.cloudinary.com/your-cloud-name/',
  },
}

Oder custom:

module.exports = {
  images: {
    loader: 'custom',
    loaderFile: './my-loader.js',
  },
}

// my-loader.js
export default function myLoader({ src, width, quality }) {
  return `https://cdn.example.com/${src}?w=${width}&q=${quality || 75}`
}

Traffic läuft über Ihr CDN statt den Next.js-Optimierer – sinnvoll bei hohem Volumen.

Responsive: sizes + CSS

<div className="image-container">
  <Image
    src="/product.jpg"
    width={1200}
    height={800}
    sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
    style={{
      width: '100%',
      height: 'auto',
    }}
    alt="Product image"
  />
</div>
.image-container {
  width: 100%;
}

@media (min-width: 640px) {
  .image-container {
    width: 50%;
  }
}

@media (min-width: 1024px) {
  .image-container {
    width: 33.333%;
  }
}

sizes und Media Queries sollten zusammenpassen.

Monitoring

Chrome DevTools → Network → Img: Größe, Zeit, Format (optimierte URLs oft mit ?w=…&q=…).

Lighthouse: LCP < 2,5 s, CLS < 0,1; Hinweise zu unoptimierten Bildern.

Nach Optimierung oft von ~60 auf 90+ Punkte.

Produktion: Google Search Console oder Vercel Analytics für Core Web Vitals.

Fazit

Kernprobleme: langsame Bilder, Config-Fehler, Layout-Sprünge.

Mit Image typischerweise:

  • 60–80 % weniger Volumen (WebP/AVIF)
  • LCP < 2,5 s (priority gezielt)
  • CLS nahe null (width/height oder fill + Parent)

Merken:

  1. Remote: remotePatterns, Server neu starten
  2. width/height oder fill + Parent-Höhe
  3. Above-the-fold: priority, Rest lazy
  4. Responsive: sizes
  5. quality: 90 / 75 / 60 je nach Rolle

<img> durch <Image> ersetzen, Lighthouse laufen lassen – oft +20 Punkte oder mehr.

Bei Problemen den Abschnitt zu häufigen Fehlern durchgehen – die meisten Fälle sind dort abgedeckt. Viele Optionen, aber wenige Kern-Props reichen für den Alltag.

Next.js Image: vollständiger Optimierungsablauf

Von Remote-Config über Performance bis CLS-Vermeidung

⏱️ Estimated time: 2 hr

  1. 1

    Step 1: Remote-Domains konfigurieren

    In next.config.js:
    • images.remotePatterns-Array
    • protocol, hostname, pathname
    • Pfadmuster einschränkbar

    Beispiel:
    images: {
    remotePatterns: [
    {
    protocol: 'https',
    hostname: 'example.com',
    pathname: '/images/**'
    }
    ]
    }

    Wichtig: Dev-Server nach Änderung neu starten
  2. 2

    Step 2: img durch Image ersetzen

    Basis:
    • import Image from 'next/image'
    • width und height (oder fill)
    • alt für SEO

    Beispiel:
    <Image
    src="/hero.jpg"
    width={800}
    height={600}
    alt="Beschreibung"
    />
  3. 3

    Step 3: CLS vermeiden

    Methode 1: feste Maße
    • width und height setzen
    • optional aspect-ratio

    Methode 2: fill
    • Parent: position relative
    • Image: fill
    • Parent mit fester Höhe

    Methode 3: placeholder
    • blurDataURL
    • placeholder="blur"
  4. 4

    Step 4: Lade-Performance optimieren

    Above-the-fold:
    • priority (bzw. preload in v16)
    • quality=90
    • im Viewport

    Sonstige Bilder:
    • Lazy Load (Default)
    • quality=75
    • sizes für Responsive

    Thumbnails:
    • quality=60
    • kleine width/height
  5. 5

    Step 5: Responsive mit sizes

    sizes teilt dem Browser mit, welche Breite nötig ist:

    <Image
    src="/hero.jpg"
    width={1200}
    height={630}
    sizes="(max-width: 768px) 100vw, 50vw"
    alt="Beschreibung"
    />

    Mobil volle Breite, Desktop halbe Breite – passende Datei wird geladen.
  6. 6

    Step 6: Testen und validieren

    Performance:
    • Lighthouse: LCP und CLS
    • Network-Tab: Größe und Format
    • WebP/AVIF prüfen

    Checkliste:
    • alle Remote-Hosts in remotePatterns
    • width/height oder fill+Parent
    • priority nur für Hero/kritisch
    • CLS nahe 0
    • Bildvolumen deutlich reduziert

FAQ

Warum der Fehler „Un-configured Host“ bei Remote-Bildern?
Aus Sicherheitsgründen erlaubt Next.js nur konfigurierte Domains. In next.config.js unter images.remotePatterns protocol, hostname und optional pathname setzen. Danach den Dev-Server neu starten.
Muss die Image-Komponente width und height haben?
Ja, um CLS zu vermeiden – außer bei importierten lokalen Bildern, wo Next.js die Maße kennt. Alternativ fill mit Parent in fester Größe oder aspect-ratio. Ohne Maße verschlechtert sich CLS.
Wie vermeide ich Layout-Verschiebung beim Bildladen?
1) width und height setzen; 2) fill mit Parent-Größe; 3) placeholder="blur" mit blurDataURL; 4) aspect-ratio. Der Container braucht vor dem Download klare Abmessungen.
Wann priority verwenden?
Für Above-the-fold: Hero, großes Logo, Artikel-Header. Bild wird sofort geladen, nicht lazy. Sparsam nutzen – zu viele priority-Bilder bremsen den First Load.
Konvertiert Image automatisch Formate?
Ja. WebP wenn unterstützt, sonst AVIF wo möglich – oft 60–80 % kleiner als JPEG/PNG, schnelleres Laden.
Wozu dient sizes?
sizes sagt dem Browser, wie breit das Bild je Breakpoint gerendert wird; zusammen mit srcset wählt er die passende Variante – wichtig, damit Mobile keine Desktop-Monsterdateien lädt.
Wie optimiere ich die Bildqualität?
quality: Hero ~90, Standard 75, Thumbnails ~60. Höher = größere Dateien. Zusätzlich kleinere width/height für Mobile nutzen.

9 Min. Lesezeit · Veröffentlicht am: 19. Dez. 2025 · Aktualisiert am: 14. Juli 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog