Web & performance
If you are searching for image optimization website, or for next/image, you are usually here: PageSpeed says LCP is an image, and you are unsure whether you have a setup or a folder. Someone runs a plugin once and calls it done. Someone dropped the hero in as a PNG in `/public` and set `priority` on three images. Someone uploads from the CMS at original size and lets the browser crop. Someone has next/image without `sizes`, so the mobile hero fetches the same file as desktop.
The speed post is about why Core Web Vitals rank, and how you measure. This one is about the image as the element that most often *is* LCP on a marketing site: format, width, CDN, and the place in the CMS that refuses to let a multi-megabyte file through. An honest pipeline is not 'we use WebP'. It is a sentence about which image may be the hero, in which format, at which width, and who says no. Without that sentence you have a plugin. You do not have a pipeline.
TL;DR
The main points
- The hero is typically LCP on a marketing site. The pipeline starts there — not in a gallery you look at last.
- Format, width and `sizes` beat 'we pressed compress'. next/image without `sizes` is still the wrong download.
- One priority hero. Three `priority` images are three LCP candidates you asked to fight.
- The CMS is part of the pipeline. An upload without a cap is how the PNG beats your Next config.
- CLS is a layout job: width/height or aspect-ratio before the image lands — not a fade you call polish.
- WordPress, Next and Shopify have the same job. The difference is where you put the no, not whether images count.
Why this even matters
A marketing site sells with images, which is exactly why they break it. The hero is what Google and the user wait for first. Google's LCP threshold is public — it is not a number we invented — and on a site like yours the LCP element is most often an image, not a text block. If the hero is an original PNG, an autoplay video you call background, or three slider frames that all fetch, you have chosen to start the conversation with a download. The pipeline is refusing that download before it is 'too late to fix in PageSpeed'.
Teams inherit the words image optimization from a plugin. In WordPress it is 'drop EWWW on it'. In a design handoff it is 'export at 2x'. In Next.js it is 'we have the Image component'. None of those is the pipeline. The pipeline is that an image cannot reach the browser without a format, a width, a CDN path and a layout slot. The plugin runs when someone remembers. The handoff lies when the CMS allows the next upload. The component lies when `sizes` is 100vw on a 200px thumb.
It is also an editorial ownership question. If marketing can upload a hero without a cap, you have given them a button that breaks LCP. That is not their fault. That is you calling the Next config a pipeline and leaving the CMS as a drive. The design-system post is tokens and components. Here the duty is simpler: one place that says no to the file before it is live. Without the no, 'we have WebP' is a sentence about last week.
We write this because 'can you just compress the images' has become a purchase you make before you have a sentence about hero, `sizes` and upload cap. An honest setup is boring: one prioritised LCP image, modern formats, real widths, dimensions in the layout, and a CMS that cannot override it. Without that sentence you have a folder. You do not have image optimization.
What an image pipeline actually is — and what next/image is not on its own
An image pipeline is the path from file to screen, with no-points: an upload cap in the CMS, a derived set of widths, a modern format (AVIF/WebP with a sane fallback), a CDN that can do that, and markup that tells the browser which file it may fetch (`srcset` + `sizes`) and how much space it occupies before it is there. It is a product choice, because it says the hero may wait for the format, not that the format may wait for the hero. Most marketing sites should have exactly that. They should not need a new DAM before they have a cap.
next/image is a tool on that path, not the path. It can derive widths, set lazy, host on Vercel or a loader you point at. It can also fetch the wrong thing if `sizes` is a lie, if you turned optimisation off to 'make it work', or if the source is already a huge PNG you dropped in `/public` without going through the loader. The component is honest when you are honest in the props. It is not an amulet you wrap around a file you refused to own.
It is not 'export to WebP once'. A format without widths is still too many pixels. A 1600px hero on a 390px screen is the wrong download in a modern wrapper. Art-direction — a different crop on mobile — is a different job from format. Fix format and width first. Fix crop when the hero cuts the face off. A slider plugin with five WebPs is five LCP candidates. One image, one crop, one `priority`. The rest lazy.
And it is not turning images off to chase a Lighthouse score. A marketing site without a hero is a different product. The pipeline lets you have the image and the LCP. If you remove the hero to 'win performance' and still upload uncompressed in case studies, you have moved the score. You have not moved the habit. The speed post is why the score matters. Here is the habit that holds it.
What typically goes wrong when someone says we have image optimization
The first failure is compressing the gallery and forgetting the hero. You run a batch job on case studies and leave the homepage because it 'is design'. The hero is LCP. The gallery is below the fold and may lazy-load. An honest first step is pointing at the LCP element in PageSpeed Insights — a tool you can run yourself — and fixing that image before you build a DAM dream. If you cannot say which file is LCP, you are not ready for a pipeline. You are ready to measure.
The second failure is `sizes` as copy-paste. `100vw` on a card in a three-column grid is asking mobile for the desktop file, or desktop for a file that is too small and gets scaled ugly. `sizes` is the layout you already have: `(max-width: 768px) 100vw, 33vw` or whatever the grid actually is. Without that sentence `srcset` is a buffet the browser guesses wrong. next/image helps you derive the files. It cannot guess your CSS.
The third failure is layout shift you call animation. The image lands, the text jumps, CLS goes red. Width and height, or an aspect-ratio box, before the request. A skeleton is allowed. A fade that shoves the H1 is not polish. It is that you did not reserve the slot. The accessibility post is EAA and focus. Here the duty is to let the image have a slot, including for the person who loses the line they were reading.
The fourth failure is letting the CMS override the pipeline. WordPress with 'full size' as the Gutenberg default. A headless CMS without transforms. Shopify files you link as a CDN without widths. You have next/image on the pages a developer touched, and original uploads on the pages the editor touched this morning. The pipeline is the no in the upload: max dimension, allowed formats, a derived set, not 'we usually remember to export'. If the no only lives in the repo, you have a developer pipeline. You do not have a site pipeline.
Folder of files vs. owned pipeline — two kinds of 'we have images under control'
The honest folder
Someone exported WebP last week. The CMS can still put the original live.
- Works until the next hero arrives as a PNG from a design tool
- next/image on some routes, `<img>` on the pages the editor built
- No `sizes` — the browser guesses, and mobile fetches too much
- Is an honest temporary place, and the wrong thing to call done
The honest pipeline
Upload cap, derived widths, modern format, one LCP image, layout slot.
- The CMS refuses the file that breaks LCP — before it is on the CDN
- Markup with `srcset` and real `sizes`; `priority` only on the hero
- Dimensions in the layout, so CLS is not a fade you call design
- Is waste if you still have not pointed at which image is LCP
How to get an image pipeline you can actually keep
Without this order you get a plugin you call optimisation, and a hero you have not touched.
- 01
Point at the LCP element — then only that image, first
Run PageSpeed Insights on the homepage and the page you actually advertise. If LCP is an image, that is the pipeline's first file. Fix format, width, `priority` and layout slot on it. Do not touch the gallery yet. A DAM project that starts with every asset is how the hero survives as a PNG while you name folders. The speed post is the threshold. Here is the file.
- 02
Put the no at upload — not in a batch job someone remembers
Max dimension. Allowed formats. A derived set of widths your markup actually uses. WordPress, a headless CMS, Shopify files: same duty, different place. If the editor can put the original live, you do not have a no. You have a guideline. Guidelines lose to a deadline. A cap in the CMS does not.
- 03
Write `sizes` as the layout you have — not as 100vw everywhere
A full-width hero is `100vw`. A three-column grid is not. A card in a sidebar is not. next/image can derive `srcset`. It cannot derive your CSS. If you will not maintain `sizes`, make the layout fewer variants, not the lie global. A wrong `sizes` is an oversized download with a green 'we use Image'.
- 04
Reserve the slot before the file lands
Width/height or aspect-ratio in markup. One `priority` on the LCP hero. Lazy on the rest. No slider that fetches five frames before first paint. If you need art-direction, two images with `picture`, not one oversized crop you hide with CSS. CLS is not an aesthetics point. It is that the line someone was reading got shoved.
- 05
Give the pipeline a kill criterion for exceptions
An SVG logo should not go through a raster loader. An OG image you cannot transform should have a named exception, not 'turn optimisation off globally'. If the job was 'hero LCP', and you now have `unoptimized` on the whole site because one screenshot broke, you sold the pipeline for a file. Write the exception. Fix the loader. Do not turn the no off.
“You have image optimization when the hero has a format, a width and a no in the CMS. A folder of WebP is a hope.”
WordPress, Next.js and Shopify — same job, three places to say no
A Next.js marketing site is what we typically recommend when you want to own the markup: `next/image` or a loader against your CDN, `priority` on one hero, `sizes` that match the grid, and a CMS (headless or git) that cannot upload without a cap. Preview on the pull request shows the right file, not only the right copy. If you have the Image component and still link a PNG from `/public` on the homepage, you have a component. You do not have a pipeline. The WordPress-to-Next post is the cutover. This is the image job you take with you — or forget, and then LCP is the same on the new stack.
A WordPress site has the same job and a different no-point. The media library is the pipeline if you force sizes, webp/avif, and refuse 'full' as the default in content. A plugin you run once is a batch. The next upload wins. If you pretend a cache plugin is image optimization, you have cached the wrong download. The relaunch post is the 301s. Here it is letting Gutenberg be a place with a cap, not a drive with pretty permalinks.
Shopify is the third place you can lie the same way. The CDN can do widths if you use them in theme liquid or in your headless frontend. An `img` with a `file` URL and no width parameter is the original. An app filter you forgot after a theme switch is a batch that died. You still have an LCP image. You still need one `priority`, real sizes, and a place in admin that does not let a huge product file become the hero on a collection. The Shopify posts are when the platform is enough. This is the image the platform will not fix for you if the theme lies.
A 'we remove images to win Lighthouse' is the last job you should not buy. The marketing site should have a hero. The pipeline is how you have it without paying the LCP debt every time someone exports from Figma. If the score is only green on a page without media, you have measured a different product. Put the no in. Fix the hero. Let the gallery be lazy. It is boring. It is what holds when the editor arrives on Monday.
What you should typically do in the situation you are in
The left is what you typically say. The right is the next step we typically recommend.
Situation
PageSpeed says LCP is an image, and you have a compression plugin
Next step
Point at the file. Fix the hero's format, width and `priority`. The plugin does not touch what you have not pointed at
Situation
You have next/image, and mobile still fetches a desktop hero
Next step
`sizes` is a lie, or the source bypasses the loader. Fix the markup. Do not turn optimisation off
Situation
Marketing uploads a new hero as PNG, and LCP dies on Monday
Next step
A no in the CMS — max dimension and format — not a Slack note about remembering to export
Situation
CLS jumps when the image lands, and you put a fade on it
Next step
Reserve aspect-ratio. The fade is not the slot. The layout is the slot
Situation
A screenshot broke the loader, so you set unoptimized on the whole site
Next step
Name the exception. Fix the loader. A global unoptimized is selling the pipeline for one file
Checklist before you call it image optimization
If you are missing several of these, the sentence is next/image — the setup is a folder.
- You can point at the LCP image on the homepage and on the page you advertise
- The hero has a modern format, real widths and exactly one `priority`
- `sizes` matches the layout — not 100vw on every card
- The layout reserves space, so CLS is not a fade
- The CMS cannot put the original live without a cap
- Exceptions are named. Optimisation is not turned off globally
Questions we get again and again
What is image optimization on a website — actually?
That an image cannot reach the browser without format, width, CDN and a layout slot — and that the hero, which is most often LCP, is the first file you fix. A plugin, a hand export, an Image component without `sizes`, are pieces. The pipeline is the no: in the CMS, in the markup, in the one `priority`. If you cannot point at the LCP file, you have not optimized. You have a folder you like.
Is next/image enough on its own?
No. It derives widths and can host and lazy-load. It can also fetch the wrong thing if `sizes` is a lie, if the source lives in `/public` without the loader, or if you turned optimisation off. The component is a tool. The pipeline is an upload cap plus honest markup plus one LCP image. We see the first alone more often. That is why mobile still fetches the desktop hero with a green 'we use Next'.
Should we convert everything to AVIF or WebP right away?
Start with the LCP hero. Modern formats there, with a sane fallback the browser can use. Then the images above the fold. The gallery below the fold may lazy-load and can follow once the no in the CMS is set. A batch that converts a whole case archive while the homepage is still PNG is the wrong order. Format without widths is still too many pixels. Do both on the file the user is waiting for.
Why does the page jump when the image loads?
Because you did not reserve the slot. Width and height, or an aspect-ratio box, before the request. A fade does not fix CLS. It hides that the layout had no slot. It is the same job on WordPress, Next and Shopify. Accessibility and reading lose when the H1 is shoved. Set the dimensions. Leave lazy for what is not LCP. Do not call the jump polish.
Is this the same as having a fast site that ranks?
No. The speed post is why Core Web Vitals count, and how you measure. This one is the image as the element that most often *is* LCP on a marketing site, and the habit that holds it: cap, `sizes`, one `priority`, a no in the CMS. You can have a green lab score on a page without media and still die on the homepage on Monday. The pipeline fixes the file. It does not replace the measurement, and it does not replace the redirects you still owe after a relaunch.
If you have next/image and a hero PageSpeed still points at
Let us separate pipeline, plugin and folder.
A no in the CMS and one honest hero beat an export you remembered last week.
