Headless Next.js E-Commerce Engineering: From Shopify Bloat to 100/100 Lighthouse

By Oleh FrozPublished on December 4, 2025

A mid-market fashion marketplace was hemorrhaging 30% of its mobile traffic due to a 5-second initial load time caused by Shopify's bloated theme layer. I rebuilt the entire storefront as a headless Next.js application with Incremental Static Regeneration, webhook-driven inventory sync, and Vercel edge caching — landing a perfect 100/100 Lighthouse Performance score and increasing conversion rates by 42% within the first 60 days.

Why Shopify Themes Were the Bottleneck

The client was running a Shopify Plus store with a heavily customized Liquid theme. The theme had accumulated 14 third-party apps injecting JavaScript, a carousel library loading on every page, and unoptimized hero images served without modern format negotiation.

The damage was measurable:

  • 5.2-second Time to Interactive on a mid-range Android device over 4G.
  • Largest Contentful Paint of 4.8 seconds, placing the store firmly in the "poor" range of Google's Core Web Vitals assessment.
  • Conversion rate of 1.1% — well below the 2.5% industry benchmark for the fashion vertical.

The client's agency suggested upgrading to Shopify's Online Store 2.0 framework. I recommended a different approach: keep Shopify as the commerce engine, rip out the entire frontend, and replace it with a purpose-built Next.js application that owns every byte of JavaScript shipped to the browser.

The Architecture: Shopify as API, Next.js as Renderer

The rebuilt system treats Shopify strictly as a headless API provider. No Liquid templates exist. No Shopify theme is active. The Storefront GraphQL API handles product queries, collection filtering, and checkout creation. Everything the customer sees and interacts with is a Next.js component.

// lib/shopify.ts — Type-safe Storefront API client
interface ShopifyProduct {
  id: string;
  title: string;
  handle: string;
  priceRange: {
    minVariantPrice: { amount: string; currencyCode: string };
  };
  images: { edges: { node: { url: string; altText: string } }[] };
  availableForSale: boolean;
}

interface ShopifyResponse<T> {
  data: T;
}

export async function getProductByHandle(
  handle: string
): Promise<ShopifyProduct | null> {
  const res = await fetch(process.env.SHOPIFY_STOREFRONT_URL!, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Shopify-Storefront-Access-Token': process.env.SHOPIFY_TOKEN!,
    },
    body: JSON.stringify({
      query: `query GetProduct($handle: String!) {
        productByHandle(handle: $handle) {
          id title handle availableForSale
          priceRange { minVariantPrice { amount currencyCode } }
          images(first: 5) { edges { node { url altText } } }
        }
      }`,
      variables: { handle },
    }),
    next: { tags: [`product-${handle}`] },
  });

  const json: ShopifyResponse<{ productByHandle: ShopifyProduct | null }> =
    await res.json();
  return json.data.productByHandle;
}

Every product page is statically generated at build time via generateStaticParams. The CDN serves pre-rendered HTML — zero server computation per request.

Webhook-Driven Inventory Sync

Product prices, stock levels, and descriptions change frequently. Instead of polling the Shopify API, the system uses Shopify webhooks to trigger on-demand ISR revalidation:

Diagram showing Shopify webhook triggering a Next.js API route that calls revalidateTag for the affected product

When a product is updated in Shopify's admin panel, a products/update webhook hits a Next.js API route. That route calls revalidateTag(product-$), which invalidates only the affected product page and any collection page listing that product. The next visitor request triggers a background regeneration, and the stale page is replaced within milliseconds.

No full rebuild. No downtime. No stale inventory data shown to customers.

Image Optimization Pipeline

The original Shopify theme served uncompressed PNG product images at 2400×2400 resolution regardless of viewport. The Next.js rebuild uses the next/image component with Vercel's built-in image optimization:

  • Automatic WebP/AVIF format negotiation based on browser support.
  • Responsive srcSet generation at 640, 768, 1024, and 1280px breakpoints.
  • Lazy loading with native loading="lazy" for below-fold product grids.
  • Priority loading (priority={true}) on the hero banner and first visible product card.

This single change reduced total image payload from 4.2MB to 380KB on the average collection page.

Component Boundary Discipline

The storefront follows a strict rendering hierarchy:

  • Server Components: Product pages, collection grids, navigation, footer, structured data injection. These ship zero JavaScript.
  • Client Components: Add-to-cart button (requires state for variant selection), mobile navigation toggle, image zoom gallery, and the mini cart drawer.

The add-to-cart interaction is the only piece of client-side state management on product pages. It uses a lightweight React context — no Redux, no Zustand, no external state library.

Core Web Vitals After Migration

| Metric | Shopify Liquid Theme | Headless Next.js Build | |---|---|---| | Lighthouse Performance | 34/100 | 100/100 | | Largest Contentful Paint | 4,800ms | 620ms | | Total Blocking Time | 1,200ms | 0ms | | Cumulative Layout Shift | 0.28 | 0.00 | | Mobile Conversion Rate | 1.1% | 1.56% (+42%) |

Lighthouse audit showing perfect 100/100 performance score on the rebuilt headless storefront

What the Client Retained

The Shopify backend continues to handle checkout, payment processing, and order fulfillment. The client's operations team uses the same Shopify admin interface they already know. Nothing changed for them except that the storefront now loads instantly.

The client owns the entire Next.js codebase, the Vercel deployment, and the webhook integration. Shopify can be replaced with any headless commerce API in the future without touching the frontend.


Skip the technical debt. Let a senior engineer build your core architecture from scratch. View my custom Next.js engineering tiers on Fiverr.

    Headless Next.js E-Commerce Engineering: From Shopify Bloat to 100/100 Lighthouse | Froz | Froz Web Engineering