How We Cut a Client's Page Load Time from 8s to 1.2s
A real case study on taking a slow Next.js e-commerce site from an 8-second load to 1.2 seconds โ covering the audit process, root causes, and the exact fixes we applied.
Add cover image in Sanity
A client came to us with a Next.js e-commerce site that was taking eight seconds to load on a standard mobile connection. Their bounce rate was over 70% and conversion was essentially non-existent on mobile โ which accounted for 65% of their traffic. We had four weeks and a clear mandate: make it fast.
Here is exactly what we found and what we fixed.
**The audit: what we looked at first**
We do not start performance work by guessing. We run a structured audit using three sources: Chrome DevTools Performance tab (network throttled to Fast 3G), WebPageTest with a real mobile device in Mumbai (closest to their user base), and Lighthouse in CI to get a reproducible baseline score.
The baseline: LCP of 8.1 seconds, TBT of 4,200ms, CLS of 0.34. Lighthouse performance score: 9 out of 100. The problems were significant and layered.
**Root cause 1: unoptimised images (responsible for ~60% of the problem)**
The site was serving JPEG product images at their original upload resolution โ some files were 4MB and up โ with no compression, no next-generation formats, and no lazy loading. Every product page was downloading 20โ30 of these images on initial load.
The fix: migrated all product images to use next/image with explicit width and height props, and the priority flag on the above-the-fold hero image. Next.js automatically served WebP to browsers that support it and sized images to the viewport. Average product image download dropped from 3.2MB to 180KB per image.
**Root cause 2: a 900KB uncompressed JavaScript bundle**
The previous developer had imported the entire Lodash library when only three utility functions were needed. They had also imported a charting library for a single analytics widget that lived in the admin panel โ not even visible to customers.
The fix: replaced Lodash with direct ES module imports, removed the charting library from the customer-facing bundle entirely, and used Next.js dynamic imports for the admin-only components so they were only loaded when the admin panel was accessed.
Bundle size dropped from 900KB to 210KB after gzip.
**Root cause 3: render-blocking third-party scripts**
The site was loading Google Tag Manager, a live chat widget, and a review aggregator widget all synchronously in the document head. These scripts were blocking the main thread for over 2 seconds before the page could render anything.
The fix: moved GTM to load with the afterInteractive strategy via the Next.js Script component. The chat widget was moved to lazyOnload โ it loads after the page is fully interactive. The review widget was replaced with a static snapshot of reviews rendered server-side, with the live widget only hydrating on scroll into view using an IntersectionObserver.
**Root cause 4: no caching headers and no ISR**
The site was using getServerSideProps for every page, including product listing pages that changed at most twice a day. Every request was hitting the database, fetching product data, and building the page from scratch โ with no cache.
The fix: migrated product listing pages and individual product pages to ISR (Incremental Static Regeneration) with a 60-second revalidation window. The server now generates each page once and serves it from cache for 60 seconds. Under load, this reduced database queries per minute from 800+ to under 20 for catalogue pages.
**Root cause 5: layout shift from fonts and images**
The custom font was loading after initial render, causing visible text reflow (FOIT โ Flash of Invisible Text followed by a layout shift). Images had no explicit dimensions specified so the browser did not reserve space for them during layout.
The fix: used next/font with display swap and preloaded the primary font weight. All images got explicit dimensions. CLS dropped from 0.34 to 0.02.
**Results after four weeks**
LCP: 8.1s to 1.2s. TBT: 4,200ms to 180ms. CLS: 0.34 to 0.02. Lighthouse performance score: 9 to 94. Mobile bounce rate dropped from 73% to 41% within the first two weeks post-launch. Conversion rate on mobile increased threefold in the following month.
**The lesson**
Performance problems almost always come from the same five categories: unoptimised images, oversized JavaScript bundles, render-blocking third-party scripts, missing caching, and layout instability. You rarely need exotic solutions. You need a rigorous audit and disciplined execution of well-understood fixes.
If your site is slow, start with images. They are almost always the biggest win.
Building digital products at HN โ websites, web apps, SaaS, and AI solutions. Co-founder of HN Tech.
Want to build something like this?
Talk to Het and Neel โ get a free proposal within 48 hours.
Start a Project โ