BACK TO BLOG
DEVELOPMENT

Next.js Performance: Sub-1s Load Times

Jan 20, 2026
Reactively Team
Next.js Performance: Sub-1s Load Times

We recently optimized a Next.js 14 e-commerce site from 3.8s to 0.7s load time—resulting in a 34% increase in conversion rate and 2.4x improvement in bounce rate. Page speed directly impacts revenue: Amazon found every 100ms of latency costs them 1% in sales. Here's our complete technical playbook for achieving sub-1-second Next.js performance with perfect Core Web Vitals scores.

The Performance Baseline

Before optimization, the client's Next.js site scored:

  • PageSpeed Score: 42/100 (Mobile)
  • LCP: 4.8s (Target: <2.5s)
  • INP: 420ms (Target: <200ms)
  • CLS: 0.38 (Target: <0.1)
  • Time to First Byte: 1.2s
  • Total Bundle Size: 847KB

After our optimizations, the same site achieved a perfect 100/100 PageSpeed score with 0.7s load time. Here's how.

1. Image Optimization Strategy

Images accounted for 78% of page weight. The Next.js Image component is powerful, but needs proper configuration to achieve optimal results.

The Wrong Way (Before)

<img src="/hero-image.jpg" alt="Product" />

The Right Way (After)

import Image from 'next/image'

<Image 
  src="/hero-image.jpg"
  alt="Product showcase"
  width={1200}
  height={600}
  quality={85}
  priority
  sizes="(max-width: 768px) 100vw, 50vw"
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQ..."
/>

Key Optimizations

  • Always specify width/height: Prevents CLS (layout shift)
  • Use priority for above-fold images: Preloads critical images
  • Set quality to 85: 75 default is too low, 100 wastes bytes
  • Use placeholder blur: Better UX during loading (generate with plaiceholder package)
  • Configure sizes properly: Serves correctly sized images per viewport

Results

LCP improvement: 4.8s → 1.4s (70% faster) | Page weight: 2.1MB → 340KB (84% reduction)

2. Code Splitting & Dynamic Imports

The initial bundle included 3 chart libraries (240KB), a video player (180KB), and animations library (95KB) that most users never saw.

Before: Loading Everything

import ChartComponent from '@/components/Chart'
import VideoPlayer from '@/components/VideoPlayer'
import AnimatedModal from '@/components/Modal'

export default function Page() {
  return (
    <div>
      <ChartComponent data={stats} />
      <VideoPlayer url="/demo.mp4" />
      <AnimatedModal />
    </div>
  )
}

After: Lazy Loading Components

import dynamic from 'next/dynamic'

const ChartComponent = dynamic(() => import('@/components/Chart'), {
  loading: () => <ChartSkeleton />,
  ssr: false
})

const VideoPlayer = dynamic(() => import('@/components/VideoPlayer'), {
  loading: () => <VideoPlaceholder />
})

const AnimatedModal = dynamic(() => import('@/components/Modal'), {
  ssr: false
})

export default function Page() {
  const [showChart, setShowChart] = useState(false)
  
  return (
    <div>
      {showChart && <ChartComponent data={stats} />}
      <VideoPlayer url="/demo.mp4" />
      <AnimatedModal />
    </div>
  )
}

Results

Initial bundle: 847KB → 312KB (63% reduction) | Time to Interactive: 5.2s → 1.8s (65% faster)

3. Font Optimization

Custom fonts were causing 400ms of render blocking and significant layout shift. Next.js 14's next/font solves this elegantly.

Before: Google Fonts CDN

<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet"/>

After: Self-Hosted Optimized Fonts

import { Inter } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  weight: ['400', '600', '700'],
  display: 'swap',
  variable: '--font-inter',
  preload: true,
  fallback: ['system-ui', 'arial']
})

export default function RootLayout({ children }) {
  return (
    <html className={inter.variable}>
      <body>{children}</body>
    </html>
  )
}

Why This Works

  • Fonts are self-hosted (no external request)
  • Automatically subsets to only latin characters (smaller files)
  • Uses font-display: swap (no render blocking)
  • Eliminates layout shift with size-adjust fallback

Results

CLS: 0.38 → 0.04 (90% improvement) | Font load time: 420ms → 0ms (instant)

4. Server-Side Rendering Strategy

Choosing the right rendering method for each page type dramatically impacts performance.

Our Rendering Decision Matrix

  • Static (SSG): Homepage, product pages, blog posts (95% of pages)
  • ISR (Revalidate: 60s): Product listings, pricing pages (content changes hourly)
  • Server Components: User dashboards, personalized content
  • Client Components: Interactive elements only (modals, dropdowns)

ISR Implementation Example

export async function generateStaticParams() {
  const products = await db.products.findMany()
  return products.map((product) => ({
    slug: product.slug
  }))
}

export const revalidate = 60 // Revalidate every 60 seconds

export default async function ProductPage({ params }) {
  const product = await db.products.findUnique({
    where: { slug: params.slug }
  })
  
  return <ProductDetails product={product} />
}

Results

TTFB: 1.2s → 180ms (85% faster) | Server costs: Reduced by 67%

5. Database Query Optimization

Slow database queries were the bottleneck. We implemented strategic caching and query optimization.

Before: N+1 Query Problem

const products = await db.products.findMany()
  
for (const product of products) {
  product.category = await db.categories.findUnique({
    where: { id: product.categoryId }
  })
}

After: Eager Loading + Redis Caching

import { redis } from '@/lib/redis'

const cacheKey = 'products:with-categories'
const cached = await redis.get(cacheKey)

if (cached) return JSON.parse(cached)

const products = await db.products.findMany({
  include: {
    category: true,
    images: { take: 1 }
  }
})

await redis.setex(cacheKey, 300, JSON.stringify(products))
return products

Results

Database queries: 247 per page → 3 per page | Query time: 840ms → 12ms (98% faster)

6. Third-Party Script Management

Google Analytics, Facebook Pixel, and Intercom were blocking rendering. Next.js Script component with proper strategy fixes this.

Strategic Script Loading

import Script from 'next/script'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        
        {/* Critical: Load after page interactive */}
        <Script 
          src="https://www.googletagmanager.com/gtag/js" 
          strategy="afterInteractive"
        />
        
        {/* Non-critical: Load when browser idle */}
        <Script 
          src="https://www.facebook.com/tr"
          strategy="lazyOnload"
        />
        
        <Script 
          src="https://widget.intercom.io"
          strategy="lazyOnload"
        />
      </body>
    </html>
  )
}

Strategy Breakdown

  • beforeInteractive: Critical scripts that must load before page is interactive (rare)
  • afterInteractive: Analytics, ads - important but not critical
  • lazyOnload: Chat widgets, feedback tools - load when browser has idle time

Results

INP: 420ms → 140ms (67% improvement) | Blocking time: 680ms → 0ms

7. Build-Time Optimizations

Next.js Config Optimizations

// next.config.js
module.exports = {
  compiler: {
    removeConsole: process.env.NODE_ENV === 'production'
  },
  
  images: {
    formats: ['image/avif', 'image/webp'],
    deviceSizes: [640, 750, 828, 1080, 1200],
    minimumCacheTTL: 31536000
  },
  
  experimental: {
    optimizePackageImports: ['lucide-react', '@headlessui/react']
  },
  
  webpack: (config) => {
    config.optimization.splitChunks = {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          priority: 10
        }
      }
    }
    return config
  }
}

Final Results: Before vs After

BEFORE

  • PageSpeed: 42/100
  • Load Time: 3.8s
  • LCP: 4.8s
  • INP: 420ms
  • CLS: 0.38
  • Bundle: 847KB
  • Conversion: 2.1%

AFTER

  • PageSpeed: 100/100 ✓
  • Load Time: 0.7s ✓
  • LCP: 1.2s ✓
  • INP: 140ms ✓
  • CLS: 0.04 ✓
  • Bundle: 312KB ✓
  • Conversion: 2.8% (+34%)

Business Impact

  • Revenue: +£47k monthly (from conversion rate improvement)
  • Bounce Rate: 68% → 43% (2.4x improvement)
  • SEO Rankings: Average position 12.4 → 7.8 (page speed is a ranking factor)
  • Mobile Traffic: +89% (better mobile experience)
  • Server Costs: £840/month → £280/month (67% reduction)

Quick Wins Checklist

Start here for immediate improvements:

  • ✓ Run PageSpeed Insights to identify biggest issues
  • ✓ Convert all img tags to Next/Image with proper sizing
  • ✓ Switch to next/font for typography
  • ✓ Dynamic import any component over 50KB
  • ✓ Add Redis caching to frequently accessed data
  • ✓ Move third-party scripts to lazyOnload strategy
  • ✓ Enable ISR for semi-static content
  • ✓ Compress images (use Squoosh or Sharp)

Performance isn't a one-time optimization—it's an ongoing practice. But these techniques will get you 80% of the way there, and that 80% translates directly to revenue. Every 100ms you save is money in the bank.

Ready to Work Together?

Let's discuss how we can help you achieve similar results for your business.

GET IN TOUCH
Next.js Performance: Sub-1s Load Times | Reactively. Digital Marketing