The Slowest Page in Your App Isn’t Broken — It’s Just Heavy
You just shipped a killer new feature.
CI passed. QA loved it. Designers approved it. Everything deployed perfectly.
You open production — ready for that dopamine rush — and then your heart sinks.
A loading spinner stares back at you… for nine seconds.
No errors. No broken layout. No warnings in the console.
You click to another page — it loads instantly.
Back again? Still molasses.
That moment? I’ve felt it more times than I care to admit. And more times than not, the culprit isn’t broken code. It was images — massive, uncompressed, poorly served, and completely ignored during the release. This guide will show you how to spot the problem instantly, clean it up correctly, and build lasting image hygiene into your team’s process.
How to Catch Images Slowing You Down
While working on a cross-functional team, we came across this exact scenario. We had an ecosystem of three React + TypeScript UIs and noticed bizarre, inconsistent load times. At first, I assumed it was backend latency but just to rule out frontend, I ran Lighthouse and GTmetrix.
The problem jumped out at me in red.
We were loading multiple 10MB product images on our product listing page — one of the most critical views in our e-commerce app. Here are three quick ways to catch this issue before it hits your users:
1. Lighthouse (Chrome DevTools)
Steps:
- Right-click on the page → “Inspect”
- Click the Lighthouse tab
- Select “Navigation” and “Mobile”
- Click Analyze page load
Steps:
Click Analyze page load
Right-click on the page → “Inspect”
Click the Lighthouse tab
Select “Navigation” and “Mobile”
Check for:
- “Serve images in next-gen formats”
- “Efficiently encode images”
- “Properly size images”
If your LCP (Largest Contentful Paint) is tied to an image, and it’s slow, you’ve found your bottleneck.
2. GTmetrix
Head to gtmetrix.com, drop in your URL, and run the test.
You’ll get a full audit of your asset weights and paint times.

- Watch for “Avoid enormous network payloads”
- Review transfer sizes — images above 1MB are almost always avoidable
- Use the Waterfall tab to visualize where load is blocked
3. Chrome DevTools > Network Tab
Steps:
- Right-click → “Inspect”
- Click Network
- Refresh the page with Disable Cache enabled
- Filter by
img

Sort by Size and Time to spot:
- Oversized images being served to small viewports
- Duplicate variants of the same asset
- Missing cache headers on assets that rarely change
Now What? (Once You Spot Image Issues)
Let’s say Lighthouse screams about LCP. GTmetrix flags 5MB of JPEGs. What now? Here’s what to fix first:
Tools for Optimizing Images in Your React + TypeScript App
If you’re not using a built-in solution like Next.js Image or Astro’s Image
, here are two great tools to bake into your pipeline:
1. Sharp
- Super-fast image processor using libvips (way lighter than ImageMagick)
- Resize, convert, compress, or generate responsive variants
- Can be run in a build script or CLI
2. imagemin
- Plugin-based compression (JPEG, PNG, WebP, SVG)
- Easy integration into Webpack or Vite via plugins
- Use it to minify all assets in
/public
before deploy
Principles for Optimized Images
I’ve worked in previous ecosystems where images were our main online offering. Digitizing and modernizing the largest comic archive on the web, I learned some very painful lessons. To ensure problems like the one above doesn’t rear its abnormally large head, follow these simple rules. Many of these will require buy in from other functional teams like Design, Product, and DevOps.
✅ Pick the Right Format
As of the current date, prefer the image formats below. Go through the different types of images your application will be dealing with and go down the list in order:
- SVG: Usually great for logos, icons, illustrated imagery. Is the source of these images always from vector-based products like Illustrator, Inkscape, etc? Is .svg a provided format offered for the image?
### Good
The latest and great for rasterized images. AVIF and WebP are highly optimized for the web and currently the tightest squeeze we have to get the last bit of "blood from the turnip" as far as images are concerned.
- AVIF: AVIF is a highly compressed and technically has better transparency than WebP.
- WebP: These formats are usually generated from a JPG/PNG. There are plenty of packages, extensions, and plugins out there that can generate webP/AVIF for your application.
- JPEG: For photos, compressed at 60–80% quality
- PNG: When transparency is required
- GIF: Last resort. Prefer animated SVG or sprite sheets
✅ Use Responsive Techniques
From 2022 Proposed Conventions:
- Use `srcset` and `sizes` attributes
- Avoid relying on CSS to scale down large assets
- Prefer `` for format fallbacks or art direction
✅ Lazy Load Intelligently
From Engineer Forum:
- Use `loading="lazy"` for anything off-screen
- Avoid lazy loading hero or above-the-fold content
- Use LQIP (Low-Quality Image Placeholder) with blur transitions
✅ Preload What Matters Most
Use this for your most important image (e.g. homepage banner or hero):
Only preload one or two assets max — more is wasteful.
Bonus: Protecting Creative Assets (Without Overengineering)
Your images may be functional, but if they’re creator-made, licensed, or strategic — protect them accordingly.
- Use canonical URLs in your metadata to help search engines credit the original source.
- Watermark high-value creator or internal images.
- Print stylesheet trick: hide or watermark images in print view to prevent free reprints.
- Monitor image theft via Google Analytics or Search Console alerts.
This doesn’t require a DMCA lawyer — it just means respecting your team’s work and protecting what you ship.
Final Thoughts
It’s easy to overlook images when debugging performance — especially when everything else “looks fine.”
But they’re sneaky.
Unoptimized images hide behind fast CPUs, CDN caches, and small data sets — until one day, your user opens a page, and everything crawls.
Catch it early. Fix it permanently.
And next time your app feels slow — ask yourself:
“Is it actually slow… or just heavy?”