
Je suis Mathieu Ponton, Co-Founder & ingénieur logiciel chez Apogée Consult à Lyon. Ingénieur diplômé de Polytech Lyon (Informatique), j'ai fait trois ans en apprentissage, partagés entre la Métropole de Lyon (inclusion numérique avec Res'in et sobriété énergétique avec Écolyo) et Superwyze, une startup medtech (POCs, dont certains aujourd'hui industrialisés, et travail sur des codebases existantes). J'ai livré plus de 10 projets en production (web, mobile et IA / RAG) pour des PME, startups et organisations publiques.
next/image : les 4 configurations où il dégrade les performances plutôt que de les améliorer
- nextjs
next/image améliore les performances dans la plupart des cas, mais pas tous. Quatre configurations concrètes où il fait plus de mal que de bien, et comment les corriger.
next/image : les 4 configurations où il dégrade les performances plutôt que de les améliorer
next/image est souvent présenté comme une optimisation automatique. Remplacez <img> par <Image> et vos Web Vitals s'améliorent. C'est vrai dans le cas nominal. Mais on a diagnostiqué plusieurs projets où next/image était la cause directe de régressions sur le LCP, parfois de plusieurs centaines de millisecondes.
Voici les quatre configurations problématiques qu'on a rencontrées, avec les diagnostics et les corrections.
Cas 1 : l'image LCP sans priority
C'est le cas le plus fréquent et le plus impactant. next/image applique du lazy loading par défaut, l'image n'est chargée que lorsqu'elle approche du viewport. Pour la plupart des images, c'est le bon comportement. Pour l'image LCP (le Largest Contentful Paint), c'est catastrophique.
L'image LCP est, par définition, visible au-dessus de la ligne de flottaison. La charger en lazy loading signifie qu'elle n'est pas découverte par le navigateur pendant le parsing HTML, elle attend que le JavaScript hydrate la page et calcule le viewport. Sur mobile, ça peut ajouter 800ms à 1,5 seconde sur le LCP.
// Problème : le hero image est chargé en lazy par défaut
<Image src="/hero.jpg" alt="..." width={1200} height={600} />
// Correction : priority désactive le lazy loading et ajoute un preload link
<Image
src="/hero.jpg"
alt="..."
width={1200}
height={600}
priority
/>La prop priority fait deux choses : elle retire le loading="lazy" et elle injecte un <link rel="preload"> dans le <head>. Le navigateur peut ainsi découvrir et télécharger l'image dès le parsing du HTML, sans attendre l'exécution du JavaScript.
La règle : toute image visible above-the-fold sur le viewport mobile doit avoir priority. Généralement, c'est une ou deux images par page.
Cas 2 : AVIF activé sur une infrastructure qui le sert lentement
next/image sert les images en AVIF par défaut si le navigateur le supporte. AVIF offre une compression supérieure à WebP, des fichiers 30 à 50% plus légers. Mais l'encodage AVIF est significativement plus lent que WebP.
Sur Vercel, l'optimisation se fait à la première requête et est mise en cache. Sur une infrastructure auto-hébergée avec un serveur d'optimisation d'images sous-dimensionné, la première requête AVIF peut prendre plusieurs secondes, bloquant le LCP de la première visite.
// next.config.ts, désactiver AVIF si l'infra ne le supporte pas
export default {
images: {
formats: ["image/webp"], // WebP uniquement, pas d'AVIF
},
}Comment diagnostiquer : ouvrir l'onglet Network de Chrome DevTools sur une visite en navigation privée (cache vide), filtrer sur les images, et vérifier le temps de réponse de la première image optimisée. Un temps supérieur à 500ms indique un problème d'encodage côté serveur.
Sur les projets auto-hébergés avec Sharp comme backend d'optimisation, on configure systématiquement formats: ["image/webp"] et on active AVIF uniquement si l'infrastructure est dimensionnée pour l'encodage à la demande.
Cas 3 : images externes sans remotePatterns correctement configuré
Quand une image vient d'un domaine externe (CMS headless, CDN d'assets, service d'avatar), next/image doit être configuré pour accepter ce domaine. Si la configuration est manquante ou incorrecte, Next.js sert un placeholder d'erreur ou affiche une image cassée.
Certaines équipes contournent ce problème en utilisant une balise <img> standard pour les images externes, perdant tous les bénéfices de l'optimisation. D'autres utilisent unoptimized={true} sur le composant, ce qui coupe l'optimisation sans résoudre l'architecture.
// next.config.ts, configuration correcte des domaines externes
export default {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "assets.mon-cms.io",
port: "",
pathname: "/images/**",
},
],
},
}Le vrai problème de performance arrive quand on configure remotePatterns avec un wildcard trop large (hostname: "**"). Next.js doit alors tenter d'optimiser des images depuis n'importe quel domaine, y compris des domaines qui servent des images non optimisables (SVG animés, images dans des formats non supportés), ce qui génère des erreurs silencieuses et des dégradations de cache.
Cas 4 : fill sans conteneur de taille définie
La prop fill permet de remplir un conteneur parent sans connaître les dimensions exactes de l'image. C'est utile pour les galeries, les images de fond, les thumbnails dont le ratio varie. Mais sans conteneur de taille explicite, next/image ne peut pas calculer les bons srcset, il sert souvent une image surdimensionnée ou génère des layout shifts.
// Problème : le conteneur n'a pas de taille définie, comportement imprévisible
<div>
<Image src="/photo.jpg" alt="..." fill />
</div>
// Correct : conteneur avec position relative et taille explicite
<div style={{ position: "relative", width: "400px", height: "300px" }}>
<Image src="/photo.jpg" alt="..." fill style={{ objectFit: "cover" }} />
</div>Un corollaire : fill sans sizes correctement renseigné force le navigateur à télécharger une image large par défaut. La prop sizes indique au navigateur quelle largeur réelle l'image occupe à différents breakpoints, sans elle, le navigateur assume que l'image fait 100vw.
<Image
src="/photo.jpg"
alt="..."
fill
sizes="(max-width: 768px) 100vw, 50vw"
style={{ objectFit: "cover" }}
/>Comment auditer rapidement
Pour identifier rapidement ces quatre cas sur un projet :
- Ouvrir Lighthouse, lancer un audit sur mobile, regarder l'opportunité "Properly size images" et les warnings LCP.
- Dans DevTools Network, filtrer les images et vérifier les Content-Type, les images LCP doivent arriver vite et en AVIF ou WebP.
- Chercher dans le code tous les composants
Imagesanspriorityet vérifier lesquels sont above-the-fold. - Chercher les
Imageavecunoptimized={true}oufillsanssizes, ce sont des candidats à corriger.
La question qui reste ouverte : Next.js proposera-t-il un jour un mode d'audit automatique qui détecte les mauvaises configurations de next/image au build, plutôt que de laisser ces problèmes atteindre la production ?