next/image στο Next.js 15: Πλήρης Οδηγός για Image Optimization, LCP και Core Web Vitals (2026)

Πλήρης οδηγός για το next/image στο Next.js 15: ρύθμιση sizes, fill, priority, remotePatterns, AVIF/WebP και βελτιστοποίηση LCP/Core Web Vitals.

next/image Οδηγός Next.js 15 (2026)

Ενημερώθηκε: 22 Ιουνίου 2026

Το next/image είναι το ενσωματωμένο component του Next.js 15 που βελτιστοποιεί αυτόματα τις εικόνες με lazy loading, responsive sizing, AVIF/WebP conversion και placeholder blur, μειώνοντας τον χρόνο LCP κατά 40-70% σε σχέση με το απλό <img>. Σε αυτόν τον οδηγό καλύπτω πώς να ρυθμίσετε σωστά sizes, fill, priority, remotePatterns, καθώς και πώς να αποφύγετε τα συνηθισμένα λάθη που έχω δει σε production έργα με Next.js App Router.

  • Το next/image στο Next.js 15 παράγει αυτόματα AVIF και WebP, εφαρμόζει lazy loading και επιστρέφει responsive srcset χωρίς επιπλέον configuration.
  • Χρησιμοποιήστε priority μόνο στην εικόνα LCP (συνήθως το hero). Η υπερβολική χρήση του ακυρώνει τα κέρδη του lazy loading.
  • Για εξωτερικές εικόνες (CMS, S3, Cloudinary), πρέπει να δηλώσετε remotePatterns στο next.config.js από το Next.js 12.3+.
  • Το sizes attribute είναι υποχρεωτικό όταν χρησιμοποιείτε fill, αλλιώς το πρόγραμμα περιήγησης κατεβάζει την μεγαλύτερη διαθέσιμη εκδοχή.
  • Το placeholder="blur" με blurDataURL βελτιώνει το perceived performance και το Cumulative Layout Shift (CLS).

Τι είναι το next/image και πώς διαφέρει από το <img>

Το next/image είναι ένα React component που επεκτείνει το standard HTML <img> με αυτόματη βελτιστοποίηση εικόνων στο build-time και στο on-demand request-time. Σε αντίθεση με το απλό <img>, το next/image κάνει αυτόματα τα εξής χωρίς να χρειάζεται επιπλέον κώδικα: παράγει πολλαπλά μεγέθη της ίδιας εικόνας μέσω srcset, μετατρέπει τα PNG/JPEG σε AVIF ή WebP ανάλογα με τον client, εφαρμόζει lazy loading με IntersectionObserver, και εμποδίζει το Cumulative Layout Shift με aspect-ratio placeholders.

Έχω δουλέψει με Next.js από τις pages-only μέρες (όταν χρειαζόμασταν third-party libraries όπως το react-lazy-load-image-component), και το next/image έχει εξελιχθεί σημαντικά. Στο Next.js 15, το Image Optimization API τρέχει αυτόματα στο edge runtime του Vercel, με αποτέλεσμα η πρώτη εικόνα ενός νέου μεγέθους να βελτιστοποιείται σε milliseconds. Επιπλέον, το cache TTL αυξήθηκε σε 4 ώρες by default και υπάρχει νέα ρύθμιση contentDispositionType για security headers.

Σύμφωνα με την επίσημη τεκμηρίωση Next.js Image, η χρήση του component είναι από τους πιο αποτελεσματικούς τρόπους βελτίωσης του Largest Contentful Paint (LCP), που αποτελεί κρίσιμο Core Web Vital για το ranking στη Google.

Βασική χρήση του next/image στο App Router

Για static (local) εικόνες που βρίσκονται στο /public ή εισάγονται απευθείας, το Next.js διαβάζει τις διαστάσεις από το αρχείο κατά το build:

// app/page.tsx
import Image from 'next/image'
import heroImage from '@/public/hero.jpg'

export default function HomePage() {
  return (
    <Image
      src={heroImage}
      alt="Hero banner για το dashboard του 2026"
      placeholder="blur"
      priority
    />
  )
}

Παρατηρήστε ότι δεν χρειάζομαι width ή height. Το static import τα υπολογίζει αυτόματα και το placeholder="blur" δημιουργεί ένα μικρό base64 placeholder από την ίδια την εικόνα. Για εικόνες με γνωστές διαστάσεις από URL string, πρέπει να δηλώσω χειροκίνητα width/height:

<Image
  src="/products/laptop.webp"
  alt="MacBook Pro 16 ιντσών"
  width={800}
  height={600}
  className="rounded-lg shadow"
/>

Το alt δεν είναι προαιρετικό. Από το Next.js 13.5+ το ESLint plugin το επιβάλλει. Κάθε εικόνα πρέπει να έχει ουσιαστική περιγραφή για accessibility (WCAG 2.1) και SEO. Αν θέλετε να εμβαθύνετε στα best practices για routes και layouts, δείτε τον πλήρη οδηγό για data fetching και caching στο App Router.

Πότε να χρησιμοποιήσετε fill αντί για width/height

Όταν δεν γνωρίζετε εκ των προτέρων τις διαστάσεις (π.χ. εικόνες από CMS, αλλαγή μεγέθους ανά viewport), χρησιμοποιήστε το fill prop. Αυτό κάνει την εικόνα να καταλάβει τον γονικό container, ο οποίος ΠΡΕΠΕΙ να έχει position: relative ή absolute:

<div className="relative aspect-video w-full">
  <Image
    src={post.coverImage}
    alt={post.title}
    fill
    sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
    style={{ objectFit: 'cover' }}
  />
</div>

Στην πράξη, το fill ταιριάζει σε grid layouts, card components και hero sections όπου το aspect ratio ορίζεται από CSS. Αν το aspect ratio είναι σταθερό και γνωστό, το width/height δίνει καλύτερα CLS scores, γιατί το Next.js εισάγει aspect-ratio CSS αυτόματα.

Πώς λειτουργεί το sizes και τα responsive images

Το sizes attribute είναι media query που λέει στο πρόγραμμα περιήγησης πόσο χώρο θα καταλάβει η εικόνα σε διάφορα breakpoints, πριν φορτωθεί το CSS. Το Next.js το χρησιμοποιεί για να δημιουργήσει το σωστό srcset:

// Παράδειγμα από production e-commerce site
<Image
  src="/products/sneaker.jpg"
  alt="Nike Air Max 2026"
  fill
  sizes="(max-width: 640px) 100vw,
         (max-width: 1024px) 50vw,
         (max-width: 1440px) 33vw,
         400px"
/>

Στο παραπάνω παράδειγμα: σε mobile (<640px) η εικόνα παίρνει όλο το πλάτος, σε tablet τα μισά, σε desktop το 1/3, και σε wide screens 400px σταθερά. Ο browser διαλέγει το βέλτιστο μέγεθος από το srcset. Τα default device sizes που χρησιμοποιεί το Next.js είναι: 640, 750, 828, 1080, 1200, 1920, 2048, 3840. Μπορείτε να τα παραμετροποιήσετε στο next.config.js:

// next.config.js
module.exports = {
  images: {
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  }
}

Τα imageSizes χρησιμοποιούνται για μικρές εικόνες (avatars, icons) όταν το sizes είναι μικρότερο από το ελάχιστο deviceSize. Όσο πιο στενά ορίσετε το sizes, τόσο μικρότερο payload θα κατέβει.

Ρύθμιση remotePatterns για εξωτερικές εικόνες

Αν τραβάτε εικόνες από CMS όπως Sanity, Contentful, Strapi, ή από S3/Cloudflare R2, πρέπει να δηλώσετε ρητά τα επιτρεπόμενα domains για ασφάλεια. Το παλαιότερο domains array έχει deprecated από το Next.js 14. Χρησιμοποιήστε remotePatterns:

// next.config.js (Next.js 15)
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.sanity.io',
        port: '',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '**.amazonaws.com',
      },
    ],
  },
}

Το wildcard ** στο hostname (διαθέσιμο από Next.js 14.1) επιτρέπει οποιοδήποτε subdomain. Αν δεν δηλώσετε το pattern, το Next.js θα ρίξει UnconfiguredHost error. Για development, μπορείτε να χρησιμοποιήσετε hostname: 'localhost' για local mock servers.

Πώς να βελτιστοποιήσετε το LCP με priority

Το priority prop πρέπει να μπει ΜΟΝΟ στην εικόνα που είναι το Largest Contentful Paint (LCP) element της σελίδας, συνήθως το hero banner above-the-fold. Όταν το θέτετε, το Next.js: (α) απενεργοποιεί το lazy loading, (β) εφαρμόζει fetchpriority="high", και (γ) εισάγει preload link tag στο <head>.

<Image
  src="/landing/hero-2026.jpg"
  alt="Dashboard analytics 2026"
  width={1920}
  height={1080}
  priority
  sizes="100vw"
/>

Στην εμπειρία μου, το πιο συχνό λάθος είναι να βάζουν developers priority σε όλες τις εικόνες "για σιγουριά". Honestly, αυτό κάνει το ακριβώς αντίθετο: ο browser αναγκάζεται να κατεβάσει 10+ εικόνες παράλληλα, καθυστερώντας το critical path και ρίχνοντας το LCP score από 1.8s σε 3.5s+. Χρησιμοποιήστε PageSpeed Insights για να ταυτοποιήσετε ποιο element είναι πραγματικά το LCP πριν προσθέσετε priority.

Για routing patterns που επηρεάζουν το πότε φορτώνονται οι εικόνες, δείτε τον οδηγό για Streaming και Partial Prerendering, που εξηγεί πώς το PPR επιτρέπει να γίνει stream το LCP image πριν από το rest of the page.

Placeholder blur και χειροκίνητα blurDataURL

Το placeholder="blur" δείχνει μια θολή, χαμηλής ανάλυσης έκδοση της εικόνας μέχρι να φορτώσει η πλήρης. Για static imports λειτουργεί αυτόματα. Για URL strings, χρειάζεστε χειροκίνητο blurDataURL (base64-encoded):

<Image
  src={post.coverImage}
  alt={post.title}
  width={800}
  height={450}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
/>

Για CMS workflows, παράγω τα blurDataURL με το plaiceholder library κατά το build ή σε server action:

// lib/image-placeholder.ts
import { getPlaiceholder } from 'plaiceholder'

export async function getBlurDataURL(src: string) {
  const buffer = await fetch(src).then(r => r.arrayBuffer())
  const { base64 } = await getPlaiceholder(Buffer.from(buffer))
  return base64
}

Εναλλακτικά, μπορείτε να χρησιμοποιήσετε placeholder="empty" (default) ή placeholder="data:image/svg+xml;..." για ένα δικό σας SVG shimmer effect. Σε e-commerce καταλόγους με 500+ εικόνες, το blur placeholder έχει σημαντικά καλύτερο perceived performance από το άδειο πλαίσιο.

AVIF, WebP και image formats στο Next.js 15

By default, το Next.js 15 σερβίρει WebP σε browsers που το υποστηρίζουν (97% του global traffic) και πέφτει σε JPEG/PNG αλλιώς. Για AVIF (που δίνει 20-30% μικρότερα bundles), πρέπει να το ενεργοποιήσετε ρητά:

// next.config.js
module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
    minimumCacheTTL: 31536000, // 1 χρόνος
  },
}
FormatFile SizeBrowser SupportEncoding Cost
JPEGBaseline100%Χαμηλό
WebP-25-35%97%Μέτριο
AVIF-50% vs JPEG94% (2026)Υψηλό (3-5x slower)
JPEG XL-60% vs JPEGΠειραματικόΥψηλό

Το AVIF έχει σημαντικά υψηλότερο encoding cost. Το πρώτο request για κάθε νέο μέγεθος μπορεί να πάρει 1-2 seconds. Αυτό είναι αποδεκτό αν χρησιμοποιείτε σωστό cache TTL (1 χρόνος και πάνω) και Vercel/CDN στο μπροστινό μέρος. Για sites με χαμηλό traffic όπου το cold cache είναι συχνό, μένω στο WebP-only.

Custom loaders και Image CDNs (Cloudinary, Imgix)

Αν έχετε ήδη Image CDN (Cloudinary, Imgix, ImageKit, AWS CloudFront), μπορείτε να γράψετε custom loader για να αποφύγετε το διπλό processing:

// lib/cloudinary-loader.ts
'use client'

export default function cloudinaryLoader({
  src,
  width,
  quality,
}: { src: string; width: number; quality?: number }) {
  const params = [`w_${width}`, `q_${quality || 'auto'}`, 'f_auto']
  return `https://res.cloudinary.com/your-cloud/image/upload/${params.join(',')}/${src}`
}

// app/components/CloudImage.tsx
'use client'
import Image from 'next/image'
import cloudinaryLoader from '@/lib/cloudinary-loader'

export function CloudImage(props) {
  return <Image loader={cloudinaryLoader} {...props} />
}

Με αυτόν τον τρόπο, το Next.js δεν προσπαθεί να βελτιστοποιήσει την εικόνα. Απλώς generates το σωστό URL και αφήνει το CDN να κάνει τη δουλειά. Αν θέλετε να ενεργοποιήσετε καθολικό loader, βάλτε loader: 'custom' και loaderFile: './lib/cloudinary-loader.ts' στο next.config.js. Για βαθύτερη παραμετροποίηση των requests, δείτε τον οδηγό για Next.js Middleware, που εξηγεί πώς μπορείτε να προσθέσετε auth headers σε image requests.

Συχνά λάθη και troubleshooting

Συγκεντρώνω εδώ τα top issues που έχω αντιμετωπίσει με το next/image στα τελευταία 2 χρόνια production deployments. Μερικά από αυτά τα έχω φάει στη μούρη σε live deploy (κλασικά Παρασκευή απόγευμα).

  • Error: Image with src "X" has either width or height modified, but not the other. Συμβαίνει όταν εφαρμόζετε CSS που αλλάζει μόνο την μία διάσταση. Λύση: χρησιμοποιήστε style={{ height: 'auto' }} ή className που διατηρεί aspect ratio.
  • UnconfiguredHost: hostname "X" is not configured. Προσθέστε το hostname στα remotePatterns και κάντε restart τον dev server.
  • Layout shift μετά το load. Συνήθως οφείλεται σε missing width/height ή fill χωρίς position: relative στον parent. Χρησιμοποιήστε Chrome DevTools → Performance → Layout Shifts.
  • Slow image optimization on Vercel. Το πρώτο request για AVIF μπορεί να πάρει 2-3s. Αυξήστε το minimumCacheTTL και χρησιμοποιήστε priority στρατηγικά.
  • SVG images δεν βελτιστοποιούνται. By default το Next.js δεν επεξεργάζεται SVG για security reasons. Ενεργοποιήστε dangerouslyAllowSVG: true ΜΟΝΟ αν τα SVG προέρχονται από trusted source, αλλιώς υπάρχει XSS risk.

Συχνές Ερωτήσεις

Πρέπει να χρησιμοποιώ πάντα το next/image αντί για το <img>;

Σχεδόν πάντα ναι. Εξαίρεση είναι τα SVG icons (όπου το <img> ή ένα inline SVG είναι ελαφρύτερο) και πολύ μικρά avatars κάτω από 5KB που δεν χρειάζονται optimization. Για κάθε άλλη περίπτωση, το next/image προσφέρει AVIF/WebP, lazy loading και responsive srcset δωρεάν.

Γιατί η εικόνα μου εμφανίζεται μαύρη ή με 0 ύψος;

Συνήθως επειδή χρησιμοποιείτε fill και ο γονικός container δεν έχει position: relative ή ορισμένο ύψος. Προσθέστε className="relative aspect-video" ή ένα explicit height στον parent.

Πόσο κοστίζει το Image Optimization στο Vercel;

Στο Hobby tier περιλαμβάνονται 1.000 source images το μήνα. Στο Pro tier ($20/μήνα), 5.000 source images και $5 ανά επιπλέον 1.000. Σημαντικό: μετράνε source images, όχι transformations. Το ίδιο source σε 8 διαφορετικά μεγέθη μετράει σαν 1.

Μπορώ να απενεργοποιήσω εντελώς το Image Optimization;

Ναι, με unoptimized: true είτε στο next.config.js καθολικά είτε ως prop σε συγκεκριμένα Image components. Χρήσιμο για static export (output: 'export') όπου το Next.js δεν έχει runtime server.

Πώς υλοποιώ art direction (διαφορετική εικόνα ανά viewport);

Το next/image δεν υποστηρίζει native <picture> με πολλαπλά sources. Η συνηθισμένη λύση είναι να κάνετε render δύο Image components με Tailwind classes hidden md:block και md:hidden, ώστε να εμφανίζεται το σωστό ανά breakpoint.

Ben Howard
Σχετικά με τον Συγγραφέα Ben Howard

Full-stack Next.js developer who's been with the framework since pages-only days. Slowly warming up to App Router.