Skip to main content
๐Ÿš€ Have a project in mind? Get an instant cost estimate โ†’
Case StudyPerformanceNext.jsCase StudyWeb Dev

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.

NP
Neel Patel
Web Developer
1 September 2025
4 min read

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.

PerformanceNext.jsCase StudyWeb Dev
NP
Neel Patel
Web Developer

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 โ†’