What Shopify Actually Does to Your Uploads
Understanding where the platform helps you — and where it does not — is the whole game. Shopify's image pipeline does three things automatically:
- Resizing on request. Your theme requests a named size (
_400x,_1024x1024, and so on) and the CDN generates and caches that derivative. - Format negotiation. Modern browsers are served WebP where it is smaller, without you converting anything.
- Compression. Derivatives are compressed on the way out, so the file a shopper downloads is rarely the file you uploaded.
What it does not do is fix the master. Shopify caps uploads at 20 megapixels and 20 MB, and it will happily accept a file right up against those limits. The original stays the source of truth for every derivative, so noise, a bloated colour profile, or an unnecessarily large canvas propagates into every size the theme asks for.
"Shopify compresses it anyway" is true for what the browser downloads and false for the zoom view, the open-graph image, and any theme that requests the full-size asset. Those pull closer to your original than you think.
The Export Sizes That Actually Make Sense
There is a sweet spot, and it is smaller than most brands upload. The useful ceiling is set by what zoom needs, not by what your camera produces.
| Upload dimension | Typical JPEG size | Supports zoom? | Verdict |
|---|---|---|---|
| 800 × 800 | ~90 KB | No | Too small — blurs on retina |
| 1600 × 1600 | ~280 KB | Yes | Recommended default |
| 2048 × 2048 | ~450 KB | Yes | Fine for detail-heavy goods |
| 4000 × 4000 | ~4.5 MB | Yes | Wasted bytes, slower admin |
Upload square masters at 1600–2048px on the long edge. That gives Shopify enough pixels to generate a crisp 2x retina derivative for a 1000px gallery slot and a genuine zoom view, without hauling around data no shopper will ever see. Going past 2048px buys resolution that only helps if you are also selling print or doing forensic fabric inspection.
Uploaded weight is not downloaded weight, but it is a reliable proxy for how much work the CDN, your admin, and any bulk sync has to do — and for what the zoom view costs on a phone.
Format: JPEG, PNG, or WebP
Most merchants get this wrong in one specific way — they upload PNGs of products on white backgrounds. A PNG of a photographic subject is typically 3–5x the size of an equivalent JPEG, and if the background is already solid white, transparency is buying you nothing.
Upload PNG when
- The image genuinely needs transparency (a cutout dropped onto a coloured section)
- The graphic has flat colour and hard edges — a size chart, a logo, a diagram
- You are preserving a master for further editing
Upload JPEG when
- It is a photograph of a product, including on a white plate
- The background is solid and baked in
- It is a lifestyle or on-model shot
- Which is to say: nearly always
Quality 80–85 is the right JPEG setting for product photography. Above 90 you are storing compression artefacts you cannot see; below 75, gradients on matte surfaces start to band visibly — and garment shots are full of soft gradients.
You do not need to convert to WebP yourself. Shopify negotiates that per-browser. Uploading WebP masters mainly costs you compatibility with tools further down the line, for very little gain.
Export with sRGB and drop the embedded thumbnail and camera metadata. A wide-gamut profile can add hundreds of kilobytes and shifts colours unpredictably in browsers that ignore it — which is also a returns problem, not just a speed one. See duplicate product images and canonical problems for the related indexing headaches.
Where Page Speed Is Actually Lost
File size is one input to Core Web Vitals, not the whole story. On a typical Shopify product page, image-related slowness comes from four places, in roughly this order of impact:
1. The hero is lazy-loaded. The single most common own-goal. If your theme applies loading="lazy" to the first gallery image, the browser deprioritises the exact asset that defines LCP. The first image should load eagerly; everything below the fold should be lazy.
2. The theme requests an oversized derivative. A slot that renders at 600px asking for _2048x2048 downloads roughly eleven times the pixels it displays. Check what your theme's image tags actually request rather than assuming.
3. No dimensions on the tag. Without width and height (or an aspect-ratio container), the browser cannot reserve space and the page jumps as each image resolves. That is pure CLS, and it is free to fix.
4. Everything loads at once. A gallery that eagerly fetches all seven images competes with the hero for bandwidth on a mobile connection.
Notice that three of those four are theme problems, not file problems. Sensible export sizes make the ceiling lower; the theme decides how much of that ceiling you hit.
Consistent Framing Is a Speed Feature Too
This one is not obvious. When every product in a collection is framed differently — different subject scale, different aspect ratios, different amounts of empty margin — your theme cannot crop predictably, and you end up either letterboxing images or shipping larger files to cover the variance.
Standardising output framing has a compounding effect:
- Fixed aspect ratio means the grid reserves space correctly and CLS drops to near zero.
- Consistent subject scale means you can crop tighter without risk of clipping, which trims useless background pixels from every file.
- A uniform plate colour compresses better than a photographed white background full of subtle gradient noise — often 15–25% smaller at identical quality.
That last point surprises people. A real photographed "white" background is never flat; it has a gradient, sensor noise, and a slight colour cast. JPEG compression spends bits encoding all of it. A deterministically painted plate is genuinely uniform and costs almost nothing to encode.
This is part of why running product shots through a consistent pipeline — the approach behind consistent Shopify collection pages — tends to shrink average file size as a side effect, not as the goal. Retouchable's product pipelines end with a deterministic framing step for exactly this reason: measured subject, fixed scale rule, exact plate colour.
Auditing What You Already Uploaded
If your catalogue predates any of this, you are not going to re-export everything by hand. Audit first, then fix the worst offenders.
Find the heavy files. Export your products from the Shopify admin and check the image URLs, or run a crawl of your sitemap and sort by response size. You are looking for anything over about 800 KB as a served derivative. Usually a small number of products account for most of the weight — old hero shots, press images someone dropped in, PNG screenshots of size charts.
Check the hero on your five best-selling PDPs. Run each through a Core Web Vitals test on mobile. If LCP is over 2.5 seconds and the LCP element is your gallery image, you have found the problem worth fixing first. Five products will tell you what is wrong with five hundred.
| Symptom | Likely cause | Fix |
|---|---|---|
| LCP over 4s on mobile | Lazy-loaded hero image | Theme: eager-load first gallery image |
| Grid jumps while loading | No width/height attributes | Theme: add dimensions or aspect-ratio |
| Single images over 2 MB | Camera originals uploaded raw | Re-export at 2048px, JPEG q82 |
| Inconsistent crop across grid | No framing standard | Re-process to a fixed plate and scale |
Replace in place, do not duplicate. When you re-upload a corrected image, push it to the same product and position rather than adding a new one. Retouchable's Shopify connection pushes a finished image back with its filename, alt text, and gallery position — position 1 being the featured image that drives collection grids and in-store search — so a re-export lands where the old file was instead of piling up alongside it. It uses read_products, write_products scopes only; no access to orders, customers, or payment data.
Fix the export preset at the source — dimension, format, quality, colour profile — and the problem stops recurring with every new drop. See naming conventions for a product image library for the filing half of the same discipline.
A Working Default
If you want one specification to standardise on and stop thinking about it, this is a defensible default for almost any Shopify catalogue:
Then, on the theme side: eager-load the first gallery image, lazy-load the rest, give every image explicit dimensions, and make sure the requested derivative is no more than 2x the rendered slot width.
That combination gets a typical product page under 2 MB of image weight with a zoomable gallery and no visible quality loss. It is not an exotic optimisation — it is just refusing to upload files that are four times larger than anything a shopper will ever see, and refusing to let the theme deprioritise the one image that decides your LCP score.
The habit matters more than the numbers. A catalogue where every SKU is exported to the same spec stays fast as it grows. One where each drop follows whatever the photographer happened to hand over gets slower every season, and the cleanup only ever gets more expensive.