Optimisation d'images Next.js : guide complet du composant Image

Score Lighthouse : 62.
Deux semaines sur un projet Next.js, et la note performance peine à dépasser la moyenne. J’ouvre Performance : le problème saute aux yeux — LCP (Largest Contentful Paint) à 4,8 s, entièrement tiré vers le bas par les images.
J’étais perplexe. Next.js, ce n’est pas censé optimiser tout seul ? En regardant le code : le grand Hero de la page d’accueil utilisait encore un <img> brut. Sur la liste e-commerce, des dizaines de vignettes en pleine résolution, 3 à 4 Mo chacune.
J’ai compris ensuite : Next.js est puissant, mais l’optimisation d’images exige d’utiliser activement le composant Image. Bien configuré, le volume peut baisser de 60 à 80 %, et le LCP passer de 4 s à moins de 2 s.
Beaucoup, comme moi au début, trébuchent malgré Image : erreur « Un-configured Host » sur les images distantes, zone qui saute au chargement, dizaines d’options incompréhensibles. Cet article rassemble les pièges que j’ai rencontrés et leurs solutions — du début à une utilisation correcte du composant Image Next.js.
Pourquoi utiliser le composant Image Next.js ?
Les trois pièges de la balise img classique
On pourrait penser qu’une image, c’est juste <img src="xxx" alt="Description du contenu visible">. Je pensais pareil — jusqu’aux tests de performance.
Piège 1 : format non optimisé, bande passante gaspillée
Une balise img affiche le format fourni. PNG de 3 Mo → l’utilisateur télécharge 3 Mo. Les navigateurs modernes supportent WebP (−30 % vs JPEG) et AVIF (−40 % de plus). img ne choisit rien : il charge le fichier tel quel.
Piège 2 : même image quelle que soit la taille d’écran
Surtout visible sur mobile : image 2000×1500, écran 375 px de large — le navigateur télécharge tout puis réduit. Bande passante et temps perdus.
Piège 3 : décalage de mise en page (CLS)
Vous voulez cliquer un bouton, l’image apparaît, la page descend, vous cliquez ailleurs. C’est le CLS (Cumulative Layout Shift), métrique Core Web Vitals de Google, directement liée au SEO.
Les capacités d’optimisation automatique d’Image
Le composant Image de Next.js n’est pas un simple wrapper img : c’est une solution complète.
Sélection automatique du format
Image lit l’en-tête Accept du navigateur : AVIF si supporté, sinon WebP, sinon format d’origine. Zéro code supplémentaire.
En test : JPEG 500 Ko → WebP 180 Ko, AVIF 120 Ko. Sur des dizaines ou centaines d’images, l’économie est énorme.
Chargement responsive
Image génère et charge la taille adaptée à l’écran : 375 px sur mobile, 1920 px sur desktop (srcset). Manuellement sur img, c’est lourd ; avec Image, c’est automatique.
Lazy loading
Par défaut, seules les images visibles dans le viewport se chargent. Le reste attend le scroll — moins de données au premier chargement, page plus rapide.
Bien utilisé, le composant Image Next.js réduit le volume de 60 à 80 %, maintient le LCP sous 2,5 s et le CLS proche de zéro. Ce ne sont pas des chiffres théoriques : je les ai mesurés sur un vrai projet.
Bases : images locales vs distantes
Au début, la question revient souvent : pourquoi certaines images passent et d’autres plantent ? Surtout une différence : local vs distant.
Images locales : le cas le plus simple
Deux approches courantes.
Méthode 1 : import (recommandée)
import heroImage from '/public/images/hero.jpg'
import Image from 'next/image'
export default function Home() {
return (
<Image
src={heroImage}
alt="Hero image"
/>
)
}
Next.js lit largeur et hauteur au build : pas besoin de width et height. C’est ma méthode par défaut pour le local.
Méthode 2 : chemin direct
<Image
src="/images/hero.jpg"
width={1920}
height={1080}
alt="Hero image"
/>
Pour les fichiers dans public, chemin direct possible — mais width et height obligatoires, sinon erreur.
Images distantes : là où ça coince le plus
Images depuis une URL externe (stockage cloud, CDN tiers).
Erreur fréquente : « Un-configured Host »
<Image
src="https://images.unsplash.com/photo-123456"
width={800}
height={600}
alt="Sample image"
/>
Sans configuration, vous verrez souvent :
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 limite les domaines autorisés pour éviter qu’un attaquant abuse de votre API d’optimisation.
Solution : remotePatterns
Dans next.config.js (recommandé Next.js 14+) :
/** @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
Signification des champs :
protocol: https ou http, en général httpshostname: domaine, correspondance exacteport: en général videpathname:/**pour tout, ou un préfixe précis
Redémarrez le serveur de dev après modification — j’ai perdu une demi-heure une fois en oubliant ça.
Ancienne config (déconseillée)
module.exports = {
images: {
domains: ['images.unsplash.com', 's3.amazonaws.com'],
},
}
domains est déprécié depuis Next.js 14. Préférez remotePatterns, plus sûr (chemins restreignables).
Pourquoi width et height sont obligatoires
Sauf import local, il faut width et height pour éviter le CLS.
Le navigateur doit réserver l’espace avant le téléchargement. Sans dimensions, il attend la fin du chargement et la mise en page bouge.
Pour le responsive à largeur variable, voir fill plus bas.
Résoudre le décalage de mise en page (optimisation CLS)
Une page qui saute, c’est insupportable. Sur un site d’actu, la plainte numéro un : « je visais le titre, l’image a chargé, j’ai cliqué sur une pub ». Le CLS compte autant pour le SEO que pour l’UX.
Qu’est-ce que le CLS et pourquoi c’est important
CLS (Cumulative Layout Shift) mesure le déplacement des éléments pendant le chargement.
Google en fait une métrique Core Web Vitals. Au-delà de 0,1, c’est mauvais ; en dessous, c’est bon. Une page avec vingt images qui poussent le contenu à chaque chargement accumule vite un mauvais score.
Personnellement, je ferme les pages qui tremblent sans même lire le contenu.
Comment Image évite le CLS
Principe : réserver l’espace à l’avance.
Avec width et height, le navigateur trace un cadre avant le téléchargement ; l’image remplit le cadre sans déplacer le reste.
<Image
src="/product.jpg"
width={400}
height={300}
alt="Product image"
/>
CLS proche de zéro. Mais le responsive pur avec largeur fluide demande autre chose.
Images responsives : la propriété fill
fill fait remplir l’image le conteneur parent ; les dimensions viennent du CSS.
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/hero.jpg"
fill
style={{ objectFit: 'cover' }}
alt="Hero image"
/>
</div>
Points clés :
- Parent avec
position: relative - Hauteur explicite sur le parent (pas
height: autoseul) objectFit:coverremplit en rognant,containaffiche tout (bandes possibles)
Le navigateur voit la hauteur du parent et réserve l’espace — CLS maîtrisé.
sizes : indiquer quelle taille charger
Avec fill, ajoutez sizes, sinon Next.js ne sait pas quelle variante générer.
<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>
Signification de sizes :
- ≤ 768 px : 100 % de la largeur du viewport
- 768–1200 px : 50 %
- > 1200 px : 33 %
Next.js génère plusieurs tailles ; le navigateur choisit la bonne. Moins de données sur mobile, chargement plus rapide.
Cas pratiques
Hero pleine largeur (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 pour charger en priorité ; sizes="100vw" = pleine largeur viewport.
Vignette d’article (taille fixe)
<Image
src={post.thumbnail}
width={300}
height={200}
alt={post.title}
/>
Dimensions fixes : width et height suffisent.
Grille produits (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%' crée un carré 1:1 — une colonne sur mobile, deux sur tablette, trois sur desktop.
Configuration clé pour la performance
Après les bases et le CLS, quelques réglages pour gagner encore.
priority : images critiques above-the-fold
Par défaut, lazy loading : chargement à l’entrée dans le viewport. Pour le Hero ou le logo, vous voulez l’inverse.
<Image
src="/hero.jpg"
width={1920}
height={1080}
priority
alt="Hero image"
/>
Avec priority, Next.js :
- Désactive le lazy loading
- Insère un preload dans le
<head> - Améliore nettement le LCP
Sur un projet, Hero + priority : LCP 3,8 s → 2,1 s.
Quand utiliser priority ?
- Hero de la page d’accueil
- Logo (si volumineux)
- Image principale d’un article
- Toute image candidate au LCP
Ne mettez pas priority partout : vingt images en parallèle ralentissent tout. Réservez-le aux plus importantes.
Changement Next.js 16
En RC, priority devient preload :
<Image
src="/hero.jpg"
width={1920}
height={1080}
preload
alt="Hero image"
/>
Ou loading="eager" + fetchPriority="high" :
<Image
src="/hero.jpg"
width={1920}
height={1080}
loading="eager"
fetchPriority="high"
alt="Hero image"
/>
loading : stratégie de chargement
lazy(défaut) : chargement à l’approche du viewporteager: chargement immédiat
En général, lazy suffit ; eager pour le above-the-fold.
// Bas de page : lazy par défaut
<Image src="/related-1.jpg" width={300} height={200} alt="Related post" />
// Contenu principal above-the-fold
<Image src="/main-content.jpg" width={800} height={600} loading="eager" alt="Main content" />
quality : équilibre qualité / taille
quality de 1 à 100, défaut 75.
<Image
src="/product.jpg"
width={800}
height={600}
quality={90}
alt="Product image"
/>
Repères :
- Images clés above-the-fold :
quality={90} - Contenu courant :
quality={75}(défaut) - Vignettes, arrière-plans :
quality={60}
En test : 90 → 75, différence visuelle faible, −30 % de volume ; 75 → 60, encore acceptable, −20 % de plus.
Mise à jour Next.js 16 : quality devient obligatoire (limiter les abus via paramètres URL). Après migration, ajoutez-le sur chaque Image.
Formats automatiques : WebP vs AVIF
Automatique via l’en-tête Accept :
- AVIF si supporté (plus petit, encodage plus lent)
- Sinon WebP (bon compromis)
- Sinon JPEG/PNG d’origine
AVIF ≈ −30 à 40 % vs WebP ; Chrome 85+, Firefox 93+, Safari 16+ le supportent.
Exemples combinés
Hero (priorité, haute qualité)
<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>
Vignettes liste (lazy, qualité moyenne)
{posts.map(post => (
<Image
key={post.id}
src={post.thumbnail}
width={300}
height={200}
quality={75}
alt={post.title}
/>
))}
Icônes footer (lazy, basse qualité)
<Image
src="/footer-icon.png"
width={40}
height={40}
quality={60}
alt="Footer icon"
/>
Erreurs courantes et solutions
Erreur 1 : Un-configured Host
Message :
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`
Cause : URL externe sans entrée dans remotePatterns.
Solution :
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/**',
},
],
},
}
Notes :
- Redémarrer le serveur (
npm run dev) hostnameexact, pas de wildcard*.example.com- Plusieurs domaines = plusieurs objets dans le tableau
Erreur 2 : décalage / CLS élevé
Symptôme : la page saute à l’arrivée des images.
Causes :
- Pas de
width/height fillsans hauteur sur le parent
Solutions :
// ❌ Manque width/height
<Image src="/product.jpg" alt="Product" />
// ✅ Dimensions explicites
<Image src="/product.jpg" width={400} height={300} alt="Product" />
// ❌ Parent sans hauteur
<div style={{ position: 'relative', width: '100%' }}>
<Image src="/hero.jpg" fill alt="Hero" />
</div>
// ✅ Parent avec hauteur
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image src="/hero.jpg" fill alt="Hero" />
</div>
Erreur 3 : flou ou image trop lourde sur mobile
Cause : pas de sizes → défaut 100vw même si l’image n’occupe que la moitié de l’écran.
Solution :
<Image
src="/product.jpg"
width={400}
height={300}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
alt="Product"
/>
Taille fixe (vignette) : width/height sans sizes.
Erreur 4 : API dépréciées
domains (Next.js 14+)
// ❌ Déprécié
module.exports = {
images: {
domains: ['example.com'],
},
}
// ✅ remotePatterns
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}
onLoadingComplete
// ❌ Déprécié
<Image
src="/image.jpg"
width={400}
height={300}
onLoadingComplete={() => console.log('loaded')}
alt="Image"
/>
// ✅ onLoad
<Image
src="/image.jpg"
width={400}
height={300}
onLoad={() => console.log('loaded')}
alt="Image"
/>
Next.js 16 : priority → preload ou loading="eager" + fetchPriority="high".
Checklist de dépannage
- ✅
remotePatternspour les images distantes ? - ✅ Serveur redémarré après config ?
- ✅
width/heightou parent dimensionné ? - ✅ Avec
fill:position: relative+ hauteur sur le parent ? - ✅
sizescohérent avec le layout ? - ✅ Pas de
domainsouonLoadingComplete?
Astuces avancées et bonnes pratiques
placeholder pour une meilleure UX
blur (images locales importées)
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 génère un base64 flou ; effet type Instagram/Medium.
Images distantes
Fournir blurDataURL manuellement :
<Image
src="https://example.com/image.jpg"
width={800}
height={600}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
alt="Remote image"
/>
Outil en ligne blurred.dev ou génération serveur avec sharp.
empty : pas de placeholder (comportement par défaut).
Utilisation avec un CDN
Loader Cloudinary :
// next.config.js
module.exports = {
images: {
loader: 'cloudinary',
path: 'https://res.cloudinary.com/your-cloud-name/',
},
}
Loader personnalisé :
// next.config.js
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}`
}
Utile pour le trafic élevé.
Schéma responsive complet
<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%;
}
}
Alignez sizes et les media queries CSS.
Surveillance et debug
Chrome DevTools → Network → Img : taille, temps, en-têtes (format). Les URLs optimisées portent souvent ?w=xxx&q=xxx.
Lighthouse : LCP < 2,5 s, CLS < 0,1, suggestions sur les images non optimisées. Après optimisation images, je passe souvent de 60+ à 90+.
Production : Google Search Console ou Vercel Analytics pour suivre les Core Web Vitals.
Conclusion
Le composant Image Next.js résout trois problèmes : chargement lent, erreurs de config, décalage de mise en page.
Bien utilisé :
- −60 à 80 % de volume (WebP/AVIF)
- LCP sous 2,5 s (
priorityciblé) - CLS proche de zéro (dimensions ou
fill)
À retenir :
remotePatterns+ redémarrage serveurwidth/heightoufill+ hauteur parentprioritysur le above-the-fold seulementsizespour le responsivequality: 90 / 75 / 60 selon l’importance
Remplacez vos <img> par <Image>, lancez Lighthouse — je parie sur +20 points minimum.
En cas de blocage, repassez par la section erreurs courantes — la réponse s’y trouve en général. Beaucoup d’options, mais quelques réglages centraux couvrent la majorité des cas.
Processus complet d'optimisation du composant Image Next.js
De la configuration des images distantes à l'optimisation performance et la prévention du CLS
⏱️ Estimated time: 2 hr
- 1
Step 1: Configurer les domaines d'images distantes
Dans next.config.js :
• Ajouter le tableau images.remotePatterns
• Définir protocol, hostname, pathname
• Correspondance par motif de chemin
Exemple :
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
pathname: '/images/**'
}
]
}
Note : redémarrer le serveur de dev après modification - 2
Step 2: Remplacer img par le composant Image
Usage de base :
• import Image from 'next/image'
• width et height obligatoires (ou fill)
• alt pour le SEO
Exemple :
<Image
src="/hero.jpg"
width={800}
height={600}
alt="Texte descriptif"
/> - 3
Step 3: Gérer le décalage de mise en page (CLS)
Méthode 1 : dimensions fixes
• width et height requis
• aspect-ratio pour conserver les proportions
Méthode 2 : mode fill
• parent en position: relative
• fill sur Image
• hauteur explicite sur le parent
Méthode 3 : placeholder
• blurDataURL pour le flou
• placeholder="blur" - 4
Step 4: Optimiser le chargement
Images clés above-the-fold :
• attribut priority
• quality=90
• visibles dans le viewport
Autres images :
• lazy loading par défaut
• quality=75
• sizes pour le responsive
Vignettes :
• quality=60
• petites dimensions - 5
Step 5: Configurer les images responsives
Propriété sizes :
• indique la taille nécessaire par breakpoint
• le navigateur choisit la variante optimale
Exemple :
<Image
src="/hero.jpg"
width={1200}
height={630}
sizes="(max-width: 768px) 100vw, 50vw"
alt="Description"
/>
Mobile : pleine largeur ; desktop : 50 % du viewport - 6
Step 6: Tester et valider
Tests performance :
• Lighthouse pour LCP et CLS
• Network pour le chargement des images
• Vérifier WebP/AVIF
Checklist :
• Tous les domaines distants configurés
• width/height sur chaque image
• priority sur le above-the-fold
• CLS proche de 0
• Volume réduit d'au moins 60 %
FAQ
Pourquoi l'erreur « Un-configured Host » sur une image distante ?
Faut-il obligatoirement width et height sur Image ?
Comment éviter le décalage au chargement des images ?
Quand utiliser priority ?
Image convertit-il automatiquement le format ?
À quoi sert sizes ?
Comment optimiser la qualité des images ?
11 min de lecture · Publié le: 19 déc. 2025 · Mis à jour le: 27 juil. 2026
Guide complet Next.js
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Guide complet du cache Next.js : maîtriser le bon moment pour utiliser revalidate
Plongée dans les quatre couches de cache Next.js, maîtrisez revalidate, revalidatePath et revalidateTag, résolvez les données obsolètes avec un guide de dépannage complet et des bonnes pratiques
Partie 25 sur 51
Suivant
Core Web Vitals Next.js en pratique : guide complet LCP/FCP/CLS
Guide complet pour optimiser LCP, FCP et CLS dans Next.js et atteindre 90+ au Lighthouse. Plus de 10 exemples de code, pièges courants et astuces terrain.
Partie 27 sur 51



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire