Case Study: Improving Website Performance Using Next.js for an Online Store
When a mid‑size retailer asked me to revamp their online storefront, the goal was crystal clear: cut load times by at least 30 % while maintaining full e‑commerce functionality and keeping SEO intact. We had to tackle three core challenges—slow server responses, bloated client bundles, and a rigid CMS that made content updates cumbersome. The solution we chose centered on Next.js web development combined with a headless CMS and performance‑first engineering practices.
Project Overview
The retailer’s existing stack was a legacy PHP application running on shared hosting. Page load times hovered around 5 seconds on mobile, and the site suffered from high bounce rates during peak traffic. My team of five developers and I mapped out an ambitious yet realistic timeline: four weeks for architecture design, eight weeks for implementation, and one week for testing and launch.
Key metrics we tracked included:
- First Contentful Paint (FCP)
- Time to Interactive (TTI)
- Search engine ranking positions for primary product keywords
- Conversion rate on checkout pages
- Server response times during load testing
Our baseline numbers were: FCP = 3.8 s, TTI = 7.2 s, average server response 1.4 s, and a 2.5 % conversion rate on product pages.
Initial Assessment and Benchmarking
I started by running Lighthouse audits across all critical paths—home, category, product detail, cart, and checkout. The audit revealed that large image assets, unused CSS, and synchronous third‑party scripts were the primary culprits. We also discovered that the CMS’s REST API was returning more data than necessary for each request.
To quantify performance gaps, I performed a load test using k6 with 1,000 virtual users simulating realistic traffic patterns. The server peaked at 3 s response time under load, far exceeding acceptable thresholds for e‑commerce sites that aim for sub‑second responses to avoid cart abandonment.
Key Findings
- Image files were uncompressed and served in legacy formats.
- CSS was monolithic; no tree shaking.
- JavaScript bundle exceeded 2 MB on mobile.
- Third‑party analytics scripts blocked rendering.
- CMS API payloads included unused metadata fields.
With these findings, we could set concrete performance goals and design a technology stack that addressed each bottleneck. Additionally, the Lighthouse audit highlighted high CLS (Cumulative Layout Shift) scores due to unreserved image dimensions, prompting an immediate focus on layout stability in our redesign.
Choosing the Right Technology Stack
Next.js 13 was the obvious choice for its hybrid rendering capabilities—static generation (SSG) for product catalog pages and server‑side rendering (SSR) for dynamic cart interactions. It also integrates seamlessly with headless CMS solutions like Contentful, which we adopted to decouple content management from presentation.
For e‑commerce logic, I integrated Stripe for payment processing, while using Vercel’s edge functions to keep API latency low. This combination allowed us to maintain a single codebase that served both static and dynamic needs without overcomplicating deployment.
We also leveraged Docker containers for local development consistency and set up GitHub Actions CI/CD pipelines with automated linting, testing, and performance checks before each deployment.
Stack Summary
- Next.js 13 (React, TypeScript)
- Contentful headless CMS
- Stripe API for payments
- Vercel edge functions
- Docker + GitHub Actions CI/CD
- Image optimization via next/image component
- Analytics with Plausible (self‑hosted)
Choosing this stack aligned with our goals: fast, SEO‑friendly pages and a flexible content workflow. TypeScript added type safety across API routes and CMS interactions, reducing runtime errors during the build phase.
Architecture Design and Implementation
We mapped out the site’s data flow from CMS to client. Product data was fetched at build time for static pages, while cart state was managed via React Context and persisted in localStorage to survive page reloads. The checkout flow remained SSR to preserve fresh server‑side session data.
Server‑Side Rendering vs Static Generation
Static generation worked well for the 200+ product pages that rarely change, reducing server load dramatically. For dynamic content—user reviews, personalized recommendations—we used Incremental Static Regeneration (ISR) to refresh pages every five minutes without full rebuilds.
API Routes and Data Layer
Custom API routes in Next.js handled interactions with Stripe and Contentful. By caching responses at the edge using Vercel’s CDN, we cut latency for repeated data fetches by 40 %. Each route included input validation and error handling to guard against malformed requests.
Image Optimization
The next/image component automatically served WebP formats when supported, reduced file sizes via progressive JPEGs, and implemented lazy loading. We also added a custom loader to integrate with Cloudinary for on‑the‑fly transformations like cropping and resizing based on viewport dimensions. A small blur-up placeholder strategy further improved perceived performance by showing low‑resolution previews before the full image loads.
Website Optimization Techniques Applied
Beyond the architectural choices, we applied a suite of performance best practices:
- Code splitting: React.lazy for non‑essential components such as product comparison widgets.
- Tree shaking with ES modules to eliminate unused CSS and JS.
- Preloading critical assets (main CSS, hero images) using
<link rel="preload">. - Prefetching next‑page data via
next/link prefetchfor smoother navigation. - Removing unused third‑party scripts and replacing them with async or defer attributes.
- Implementing HTTP/2 push for fonts and icons to reduce round trips.
- Using
<link rel="preconnect">to key external domains (fonts, analytics) to establish early TLS handshakes.
Each technique was validated through Lighthouse before merging into the main branch. We also introduced a custom performance budget in our CI pipeline, failing builds that exceeded set thresholds. The budget included maximum bundle size, page weight, and third‑party script count, ensuring that every new feature stayed within acceptable limits.
SEO and Performance Results
After launching the new site, we re‑ran Lighthouse on all critical pages:
- FCP dropped from 3.8 s to 1.4 s (63 % improvement).
- TTI improved from 7.2 s to 2.6 s.
- Largest Contentful Paint (LCP) fell below 2.5 s, meeting Google’s Core Web Vitals target.
- Server response times under load stabilized at 0.9 s.
SEO impact was measurable as well. Within three months, organic traffic grew by 22 %, and the average position for our top product keywords improved from rank 12 to rank 4. Conversion rate on checkout pages increased from 2.5 % to 3.8 %—a 52 % lift attributable to faster page loads and a smoother user experience.
Key takeaway: By combining Next.js’s hybrid rendering with a headless CMS, you can deliver SEO‑friendly static pages while still handling dynamic e‑commerce interactions efficiently.Lessons Learned & Recommendations
In my experience, the biggest hurdle is aligning dev and ops expectations around deployment frequency. We initially planned weekly releases but shifted to a feature‑flag strategy that let us ship small increments without full redeploys.
- Start with a clear performance budget; enforce it through CI.
- Use ISR for content that changes infrequently but still needs freshness.
- Prioritize image optimization early—often the largest source of wasted bandwidth.
- Leverage edge functions to keep API latency low, especially for checkout flows.
- Maintain a clean separation between CMS data and presentation logic; this speeds up rebuilds.
- Document all cache invalidation rules so that marketing changes propagate promptly.
We also realized that while Next.js handles most client‑side optimizations automatically, manual tweaks (like custom loaders and async script handling) still provide noticeable gains. Regular monitoring with tools like Vercel Analytics and Google Search Console keeps performance on track post‑launch.
What is the biggest performance bottleneck you’ve encountered in your current e‑commerce stack, and how did you address it?