Skip to content
Production Ready — Part 18 of 30

Why Your Page Takes 10 Seconds to Load

Written by claude-sonnet-4 · Edited by claude-sonnet-4
performancecore-web-vitalsbundle-optimizationjavascriptproductionseo

The 3 AM Audit

Last year, a founder messaged me in a panic. She'd been building her SaaS product for six months. The waitlist was solid. She launched. Traffic came in. Conversions were terrible.

She thought it was her copy. She rewrote the hero section three times. She A/B tested her CTA button color. Nothing moved.

Then I pulled up her site on my phone, on a real cellular connection, and timed it.

Fourteen seconds to first meaningful content.

Her laptop — always on fast Wi-Fi, always warm-cached from development — never showed her this. She had shipped a product that real users, on real devices, in real conditions, experienced as broken.

She wasn't alone. This is one of the most common silent killers of new production apps. And in 2026, the stakes just got higher.


Why This Is Now a Business-Critical Problem

In March 2026, Google's core update formalized Interaction to Next Paint (INP) as a primary ranking signal alongside LCP and CLS, and simultaneously tightened the Largest Contentful Paint "good" threshold from 2.5 seconds down to 2.0 seconds. Analysis across 10,000 domains found that sites with LCP between 2.0s and 2.5s — which previously passed Core Web Vitals — are now flagged as "needs improvement" and have seen measurable ranking pressure.

That's not a theoretical SEO risk. One e-commerce case study in that same analysis showed: after cutting INP from 340ms to 128ms and LCP from 2.8s to 1.7s, organic traffic rose 23% in six weeks.

On the revenue side, the math is brutal: a 0.1-second improvement in load time can increase conversion rates by 8.4% and average order value by 9.2%. Snapdeal boosted conversions 30% after optimizing Core Web Vitals. Cdiscount saw a 6% revenue uplift during promotions. A site earning $50,000/day could lose $1.28 million/year from a single extra second of load time.

Your slow page isn't just annoying. It's bleeding money and search rankings simultaneously.


The Four Usual Suspects

When a page loads slowly in production, the culprit is almost always one of four things — and your dev environment hides all of them.

1. A Bloated JavaScript Bundle

This is the most common one I see in vibe-coded apps. You install a package to solve a small problem and accidentally pull in hundreds of kilobytes of code you never use.

The classic example: moment.js is 72KB minified and gzipped. day.js does almost everything moment does and weighs 2KB. If you swap just that one library, you save 70KB of JavaScript that every user has to download, parse, and execute before your page becomes interactive.

A well-documented incident describes a charting library consuming 70% of a production bundle — the developer only needed a single line chart but imported the entire library.

Five or six of these "legacy behemoths" in a modern app adds up to multiple megabytes. On a 4G connection, that's the difference between 1 second and 10 seconds.

Diagnose it:

# Install the analyzer (webpack-based projects)
npm install --save-dev webpack-bundle-analyzer

# For Vite projects
npm install --save-dev rollup-plugin-visualizer

For a Next.js project:

# Add to next.config.js or use the built-in analyzer
BUNDLE_ANALYZE=true next build

This opens an interactive treemap in your browser. Look for the biggest blocks. Anything over 100KB that isn't React itself deserves scrutiny.

2. Images Not Optimized for the Web

The hero image a designer exported as a 4MB PNG. The product photos uploaded directly from an iPhone at full resolution. These are everywhere in production apps.

Modern browsers support WebP and AVIF — formats that are 30–50% smaller than JPEG/PNG with identical visual quality. Next.js handles this automatically with the <Image> component. But if you're using a plain <img> tag, or a CMS that serves raw uploads, you're serving your users massive files over every connection.

// Bad: raw img tag with no optimization
<img src="/hero.png" alt="Hero" />

// Good: Next.js Image component with automatic WebP conversion,
// lazy loading, and proper sizing
import Image from 'next/image'

<Image
  src="/hero.png"
  alt="Hero"
  width={1200}
  height={600}
  priority  // preloads above-the-fold images
/>

For images outside Next.js, use a CDN with image transformation (Cloudinary, Imgix, or Cloudflare Images). Never serve raw uploads directly from your server.

3. Too Many Blocking Third-Party Scripts

Analytics. Chat widgets. A/B testing tools. Ad pixels. Marketing attribution trackers. Every one of these is a JavaScript file your browser has to download and execute before it can finish rendering your page.

This is what Google's INP metric is actually measuring: real-world interactivity delay. In the March 2026 case study data, one of the highest-impact fixes was "removed 14 unused GTM tags" — that single change was part of bringing INP from 340ms to 128ms.

Audit your third-party scripts:

# In Chrome DevTools:
# Network tab → filter by "third-party" → sort by size
# Look for anything over 50KB that isn't essential at load time

Load non-critical scripts after the page is interactive:

<!-- Bad: blocks rendering -->
<script src="https://analytics.example.com/track.js"></script>

<!-- Good: deferred, loads after page is interactive -->
<script src="https://analytics.example.com/track.js" defer></script>

<!-- Better for truly non-critical tools: load after interaction -->
<script>
  window.addEventListener('load', () => {
    const script = document.createElement('script')
    script.src = 'https://chat-widget.example.com/widget.js'
    document.body.appendChild(script)
  })
</script>

4. No Caching, No CDN

If every page request hits your origin server in a single region, users in other geographies are waiting for a round trip that doesn't need to happen. Static assets — JavaScript bundles, CSS, images, fonts — don't change between requests. They should be served from a CDN edge node close to the user, with proper cache headers.

Check your cache headers:

curl -I https://yourdomain.com/static/bundle.js | grep -i cache

You want to see something like:

Cache-Control: public, max-age=31536000, immutable

That tells browsers and CDNs to cache that file for a year. (Your bundler should be appending content hashes to filenames like bundle.a3f9c2.js so new deployments break the cache automatically.)

For dynamic pages, even a short cache time helps:

Cache-Control: public, max-age=60, stale-while-revalidate=3600

This serves cached content instantly while revalidating in the background — users get speed, and content stays fresh.


How to Actually Measure This

Don't test from your machine. Your laptop has a warm cache, a fast CPU, and a fiber connection. Use these instead:

PageSpeed Insights (free): pagespeed.web.dev — runs Lighthouse and shows you real-world field data from Chrome users. This is what Google uses for rankings.

WebPageTest (free): webpagetest.org — lets you test from specific geographic locations on throttled connections. Test on "Slow 3G" from a city your users actually live in.

Chrome DevTools Performance tab: Press Ctrl+Shift+I, go to Performance, hit Record, then throttle the CPU to 4x slowdown and the network to "Slow 3G." This simulates a mid-range phone on a real-world connection.

# Quick Lighthouse CLI audit
npx lighthouse https://yoursite.com --output=html --view

# Or with specific throttling settings
npx lighthouse https://yoursite.com \
  --throttling.cpuSlowdownMultiplier=4 \
  --screenEmulation.mobile=true

Once you know your baseline numbers, the 2026 targets to hit are:

  • LCP: under 2.0 seconds (tightened from 2.5s in March 2026)
  • INP: under 150ms
  • CLS: under 0.10

The Fix In Practice

For most vibe-coded apps, the biggest wins come in this order:

  1. Lazy load routes — don't ship your entire app on the first page load
  2. Replace bloated libraries — audit your bundle, swap moment.js, lodash-heavy imports, etc.
  3. Optimize images — use the framework's Image component or a CDN
  4. Defer third-party scripts — move non-essential tags to load after interactive
  5. Add a CDN — Cloudflare free tier is enough to start

Code splitting in React:

import { lazy, Suspense } from 'react'

// Instead of this (loads everything upfront):
// import Dashboard from './Dashboard'

// Do this (loads Dashboard only when user navigates to it):
const Dashboard = lazy(() => import('./Dashboard'))
const Analytics = lazy(() => import('./Analytics'))
const Settings = lazy(() => import('./Settings'))

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Router>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/analytics" element={<Analytics />} />
        <Route path="/settings" element={<Settings />} />
      </Router>
    </Suspense>
  )
}

This alone can cut your initial bundle by 50–80% for apps with multiple routes.


Performance Checklist

Before every production release, run through this list:

  • Baseline measured — PageSpeed Insights score recorded for both mobile and desktop
  • LCP under 2.0s — Largest Contentful Paint meets March 2026 threshold
  • INP under 150ms — Interaction to Next Paint passes as primary ranking signal
  • Bundle analyzed — webpack-bundle-analyzer or equivalent run; no library over 100KB that isn't justified
  • Images optimized — no raw PNG/JPEG over 200KB; WebP or AVIF served where supported
  • Third-party scripts audited — unused tags removed; non-critical scripts deferred
  • Cache headers set — static assets have long-lived cache headers with content-hash filenames
  • CDN in front of origin — at minimum Cloudflare free tier routing traffic
  • Mobile tested — manually tested on a throttled connection in Chrome DevTools
  • Performance budget set in CI — build fails if bundle size increases >5% without approval

Ask The Guild

What's the worst performance culprit you've discovered in one of your own production apps — and what was the fix? Drop it in the comments. Bonus points if you share the before/after PageSpeed scores. These real-world cases are gold for everyone in the Guild learning to ship fast.

Copy A Prompt Next

Review and debug

If this article changed how you think about the problem, copy a prompt that turns that judgment into one safe, reviewable next step.

Matching public prompts

23

Keep the task scoped, copy the prompt, then inspect one reviewable diff before the agent continues.

Need the safest first move instead? Open the curated sample prompts before you browse the broader library.

Working With AI ToolsWorking With AI Tools

v0 by Vercel — UI Components From a Text Prompt

Generate production-ready UI components with v0 and integrate them into your projects.

Preview
"I want v0 to generate a React component for this screen:
[describe the UI, data fields, visual style, empty state, loading state, and mobile behavior]
The component must:
1. work in a Next.js + Tailwind project
2. be easy to wire to real data later
Production Ready

Use this production insight inside a full build sequence

Production articles show you what breaks in the real world. The right path turns that lesson into a sequence you can ship with instead of just nodding at.

Best Next Path

Building a Real Product

Guild Member · $29/mo

Bridge demos to software people can trust: auth, billing, email, analytics, and the surrounding product plumbing.

20 lessonsIncluded with the full Guild Member library

Need the free route first?

Start with Start Here — Build Safely With AI if you want the workflow and vocabulary before you dive into the deeper path above.

T

About Tom Hundley

Tom Hundley writes for builders who need stronger technical judgment around AI-assisted software work. The Guild turns production experience into public articles, copy-paste prompts, and structured learning paths that help non-software developers supervise AI agents more safely.

Do this next

Leave this article with one concrete move. Copy the matching prompt, or start with the path that teaches the safest next skill in sequence.