PerformanceNext.jsCore Web VitalsCachingCDNImagesSEO

Website Performance Optimization: The Complete Checklist (Next.js + Core Web Vitals) for 2026

Adrijan Omičević··14 min read
Share

# What This Checklist Covers (and Why It Matters)#

Website performance optimization directly impacts conversion, SEO, and user retention. Multiple industry studies consistently show that small speed improvements move business metrics; for example, Deloitte reported that shaving 0.1s off load time can improve conversion rates on retail sites (impact varies by industry and device mix).

This guide is a Next.js-focused, production checklist covering Core Web Vitals, images, lazy loading, CDN, and caching—plus concrete before/after metrics you can use as benchmarks. If you’re early in your Next.js journey, start with Getting started with Next.js and come back here once your app is deployed.

# Baseline First: Measure Before You Optimize#

Without a baseline, “optimization” often becomes guesswork. You want field data (real users) for truth and lab data (Lighthouse) for debugging.

The Metrics That Actually Matter (Core Web Vitals)#

Core Web Vitals are evaluated at the 75th percentile of page loads, not the average. This matters because outliers (slow devices, bad networks) affect the user experience and Google’s assessment.

MetricWhat it representsGood targetCommon causes in Next.js
LCP (Largest Contentful Paint)Time to render the main content≤ 2.5sUnoptimized hero image, slow TTFB, blocking CSS/JS
INP (Interaction to Next Paint)Responsiveness to user input≤ 200msHeavy JS, long tasks, third-party scripts, excessive client components
CLS (Cumulative Layout Shift)Visual stability≤ 0.1Images without dimensions, late-loading fonts, injected UI banners

Tools: What to Use and When#

GoalToolWhy it’s useful
Field (real-user) CWVCrUX / PageSpeed InsightsShows CWV at p75; what Google uses
Lab debuggingLighthouse (Chrome DevTools)Identifies render-blocking, LCP element, long tasks
Next.js-specific profilingNext.js build output + bundle analyzerFinds large client bundles and heavy dependencies
Backend latencyAPM (Datadog/New Relic) or server logsTTFB is often the hidden bottleneck

ℹ️ Note: A common trap is “Lighthouse chasing.” You can get a 100 score while still failing CWV in the field if your real users are on slower phones and networks. Always validate improvements with field data.

Before/After Example (Realistic Next.js E-commerce PDP)#

Here’s a typical improvement pattern we see on product detail pages after fixing images, caching, and third-party scripts.

Metric (p75)BeforeAfterWhat changed
LCP4.1s2.2sOptimized hero image, preloading, CDN caching
INP320ms170msReduced client JS, deferred non-critical scripts
CLS0.210.05Fixed image sizes, stabilized font loading
TTFB900ms180msISR + CDN cache headers, reduced server work

Use this as a sanity check: if your LCP is high but TTFB is low, it’s usually front-end payload and images. If TTFB is high, look at rendering strategy and caching first.

# Next.js Rendering Strategy: Choose the Fast Path#

Next.js gives you multiple ways to render pages. Your performance profile depends heavily on this choice.

Quick Decision Matrix (SSR vs SSG vs ISR)#

Page typeRecommendedWhyTypical cache strategy
Marketing pagesSSGFastest, static HTMLCDN cache “immutable”
Blog/contentISRFreshness + speedCDN cache with revalidate
Authenticated dashboardsSSR or client fetchPer-user dataPrivate/no-store where needed
Product/category pagesISR (often)Huge SEO surface, needs updatesRevalidate by time or tags

Avoid Unnecessary Client Components#

In the Next.js App Router, server components are your default advantage. Every client component increases JS shipped to the browser, which often hurts INP.

Checklist:

  • Keep layout, navigation, and content rendering as server components.
  • Use client components only for interactive parts (filters, carts, complex forms).
  • Replace “global client wrapper” patterns with granular client islands.

If you’re building a high-performing marketing site or storefront, this often matters more than micro-optimizing JavaScript.

# Core Web Vitals Checklist (Next.js Implementation)#

1) Improve LCP: Optimize the LCP Element (Usually the Hero Image)#

In many Next.js sites, the LCP element is a large image above the fold. Treat it as critical content.

Checklist:

  • Use next/image for responsive sizing and modern formats.
  • Set priority only for true above-the-fold images.
  • Provide sizes so the browser downloads the right variant.
  • Ensure the hero image is not accidentally lazy-loaded.
TSX
// app/(marketing)/page.tsx
import Image from "next/image";
 
export default function Hero() {
  return (
    <Image
      src="/images/hero.jpg"
      alt="Product hero"
      width={1600}
      height={900}
      priority
      sizes="(max-width: 768px) 100vw, 1200px"
      style={{ width: "100%", height: "auto" }}
    />
  );
}

Why this matters: without proper sizes, mobile users may download desktop-sized images, which inflates LCP on real devices.

2) Improve INP: Reduce Main-Thread Work and Client JS#

INP typically degrades because the browser is busy executing JavaScript when the user tries to interact.

Checklist:

  • Remove heavy libraries from the client bundle (date libs, charting, WYSIWYG editors).
  • Split interactive widgets and load them only on pages that need them.
  • Replace expensive client-side state where server rendering works.

To identify large client bundles, use the analyzer.

Bash
npm i -D @next/bundle-analyzer
JavaScript
// next.config.js
const withBundleAnalyzer = require("@next/bundle-analyzer")({
  enabled: process.env.ANALYZE === "true",
});
 
module.exports = withBundleAnalyzer({
  reactStrictMode: true,
});
Bash
ANALYZE=true npm run build

Actionable rule: if a dependency is used on 10% of pages, don’t ship it to 100% of users.

3) Improve CLS: Reserve Space for Everything That Loads Late#

CLS issues often come from images, fonts, and injected UI (cookie banners, chat widgets).

Checklist:

  • Always specify width and height (or aspect ratio) for images.
  • Avoid inserting banners above content without reserving space.
  • Use font-display: swap and consistent fallback fonts to reduce layout jumps.

⚠️ Warning: A common CLS killer is a cookie consent bar that appears at the top and pushes the whole page down. Reserve space from the start or render it in a non-layout-shifting way (e.g., overlay).

# Image Optimization (Biggest LCP Lever for Most Sites)#

Images are often the majority of transferred bytes on content-heavy pages. Modern formats and correct sizing reduce bandwidth, decode time, and LCP.

The Practical Image Checklist for Next.js#

ItemTargetHow in Next.js
Use modern formatsAVIF/WebPnext/image auto-optimizes; ensure source quality
Correct responsive sizingNo oversized downloadssizes + correct layout
Avoid layout shiftsReserve spacewidth/height or stable container
Compress appropriatelyBalanced qualityPre-compress originals; avoid huge JPEGs
Optimize thumbnailsSmall and fastUse separate smaller assets or rely on image resizing

Remote Images: Configure Domains Safely#

If you load images from a CMS or CDN, whitelist domains.

JavaScript
// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      { protocol: "https", hostname: "images.example-cms.com" },
      { protocol: "https", hostname: "cdn.example.com" },
    ],
  },
};

Example: Before/After on a Blog Listing#

ItemBeforeAfter
Thumbnail size served to mobile1200px wide400–600px wide (responsive)
FormatJPEGWebP/AVIF
Total image transfer on listing3.8MB1.2MB
LCP (lab)3.2s2.0s

This improvement is common when a listing page renders 10–20 thumbnails with no sizes and no proper resizing.

# Lazy Loading (Done Right, Not Everywhere)#

Lazy loading saves bandwidth and reduces initial work, but misusing it can hurt LCP and cause jank.

What to Lazy Load#

ElementLazy load?Why
Below-the-fold imagesYesFrees bandwidth for LCP
Below-the-fold sectionsOftenReduce initial JS/HTML work
Above-the-fold hero imageNoIt’s usually the LCP element
Primary navigationNoNeeded for immediate interaction
Third-party widgets (chat, ads)Yes (defer)Often heavy and not critical

Dynamic Imports for Heavy Client Widgets#

Keep heavy components out of the initial bundle.

TSX
// app/product/[slug]/page.tsx
import dynamic from "next/dynamic";
 
const Reviews = dynamic(() => import("./Reviews"), {
  ssr: false,
  loading: () => null,
});
 
export default function ProductPage() {
  return (
    <>
      {/* main content */}
      <Reviews />
    </>
  );
}

Use this for widgets that are not needed for first render (reviews, recommendations, advanced filters).

💡 Tip: If you defer a widget that affects layout, reserve space with a fixed-height skeleton to prevent CLS.

# CDN: Reduce Latency and Stabilize Performance Globally#

A CDN improves performance by caching content closer to users and smoothing traffic spikes. For global audiences, it’s one of the highest ROI improvements.

What to Serve Through a CDN#

Asset typeCDN suitabilityNotes
Static assets (/_next/static/*)ExcellentTypically immutable and cacheable
ImagesExcellentUse image CDN or Next image optimization
HTML (SSG/ISR)GoodCache and revalidate; avoid caching personalized pages
API responsesDependsCache public data; keep private data uncached

If your app is on Vercel, you already benefit from edge caching for many assets. The remaining work is correct cache headers and choosing ISR/SSG where possible.

CDN Configuration Checklist#

  • Cache immutable assets for a long time (max-age=31536000, immutable).
  • Cache HTML for static and ISR pages according to freshness needs.
  • Bypass cache for personalized content (cookies, auth headers).
  • Enable Brotli compression if your platform supports it (most do).

# Caching Strategies (Next.js + HTTP): The Money Section#

Caching is where performance becomes predictable. You’re trying to reduce:

  • Server compute per request (TTFB)
  • Repeated DB calls
  • Variance during traffic spikes

Caching Layers You Should Consider#

LayerExamplesWhat it improves
Browser cacheCache-ControlRepeat visits, back/forward navigation
CDN/edge cacheVercel edge, CloudflareTTFB globally, traffic smoothing
Server data cacheNext.js data cache, fetch cachingSSR performance, DB load
App cacheRedisExpensive computations, shared state
Content typeSuggested headerWhen to use
Fingerprinted assetspublic, max-age=31536000, immutable/_next/static/*
Public API (fast-changing)public, s-maxage=60, stale-while-revalidate=300Lists, search suggestions
ISR HTMLPlatform-controlled + revalidateContent pages
Personalized HTMLprivate, no-storeAccount pages

If you serve an API route that returns public content, you can add caching like this:

TypeScript
// app/api/products/route.ts
export async function GET() {
  const body = JSON.stringify({ items: [] });
 
  return new Response(body, {
    headers: {
      "Content-Type": "application/json",
      "Cache-Control": "public, s-maxage=60, stale-while-revalidate=300",
    },
  });
}

This reduces repeated origin hits while keeping data acceptably fresh.

ISR in Practice: High Performance Without Stale Content Anxiety#

Incremental Static Regeneration is often the best default for SEO pages that change occasionally.

Checklist:

  • Use ISR for product, category, and content pages.
  • Revalidate by time for simplicity, or by tags when you have a CMS.
  • Confirm that your CDN honors ISR behavior (Vercel does; other setups may need tuning).

Even a modest shift from SSR to ISR can drop TTFB from 800–1200ms to 100–250ms for global users, especially under load.

# Third-Party Scripts: The Silent INP Killer#

Analytics, A/B testing, chat widgets, and tag managers frequently degrade INP due to long tasks. You don’t need to remove them—you need to control when they execute.

Checklist:

  • Audit third-party scripts and remove unused tags.
  • Load non-critical scripts after interaction or after page is stable.
  • Prefer server-side tracking where feasible.

A practical approach:

  • Keep only one analytics tool.
  • Defer chat widgets until the user scrolls or spends 10–15 seconds on the page.
  • Avoid “all pages” injection for scripts needed only on checkout or pricing.

# Network and Payload: Keep the First Load Small#

Even with perfect caching, large JS and CSS payloads hurt. The goal is not “small for the sake of small,” but fast-to-interactive.

Payload Checklist#

ItemTargetHow to achieve it
JS per routeAs low as possibleServer components, code splitting, remove heavy deps
CSS blockingMinimalAvoid giant global CSS, split per route where possible
Fonts1–2 familiesSubset fonts, preload only what’s needed
JSON dataDon’t overfetchRequest only required fields, paginate

# Operational Checklist: Prevent Performance Regressions#

Performance improvements often disappear after a few sprints. Put guardrails in place.

Add Performance Budgets#

Checklist:

  • Set a maximum JS size per route (e.g., 170–250KB gzipped as a starting point).
  • Track CWV over time (weekly) and alert on regressions.
  • Make performance part of Definition of Done for new pages.

Use Synthetic Monitoring for Critical Paths#

For high-value flows (homepage → PDP → checkout), synthetic checks catch CDN and backend issues before customers do.

Track:

  • TTFB
  • LCP
  • INP proxies (total blocking time in lab)
  • Error rates

# Complete Website Performance Optimization Checklist (Copy/Paste)#

Use this list to run a full audit.

Core Web Vitals (CWV)#

  1. 1
    Identify LCP element per template (home, listing, detail).
  2. 2
    Fix LCP with image optimization, preloading, and reduced TTFB.
  3. 3
    Reduce INP by cutting client JS, deferring third-party scripts, and avoiding big client wrappers.
  4. 4
    Reduce CLS by reserving space for images, fonts, and injected UI.

Images#

  1. 1
    Use next/image for all content images.
  2. 2
    Add sizes for responsive behavior.
  3. 3
    Use priority only for true above-the-fold images.
  4. 4
    Enforce compression and reasonable source dimensions.

Lazy Loading#

  1. 1
    Lazy load below-the-fold images and sections.
  2. 2
    Dynamic import heavy client widgets.
  3. 3
    Reserve space for lazy-loaded UI to avoid CLS.

CDN#

  1. 1
    Ensure immutable caching for fingerprinted assets.
  2. 2
    Cache public HTML/API where safe.
  3. 3
    Verify compression (Brotli) and HTTP/2/3 support.

Caching#

  1. 1
    Prefer SSG/ISR for SEO pages.
  2. 2
    Add Cache-Control headers to public API responses.
  3. 3
    Avoid caching personalized responses.
  4. 4
    Validate cache hit ratio at CDN and origin.

Next.js-Specific#

  1. 1
    Minimize client components; use server components by default.
  2. 2
    Analyze bundles and remove heavy dependencies.
  3. 3
    Keep route-level JS small with code splitting.

Proof (Metrics)#

  1. 1
    Record baseline (p75 CWV + Lighthouse + bundle sizes).
  2. 2
    Re-test after each change.
  3. 3
    Roll out gradually when changes affect caching or rendering strategy.

# Key Takeaways#

  • Optimize what drives Core Web Vitals: LCP (hero/content), INP (JS + third parties), CLS (reserved space), using field data at the 75th percentile.
  • In Next.js, performance often improves fastest by reducing client components and shipping less JavaScript to the browser.
  • Image work is usually the biggest win: use next/image, correct sizes, modern formats, and avoid lazy-loading the LCP image.
  • Treat caching as a system: SSG/ISR + correct Cache-Control + CDN can drop TTFB from ~1s to ~200ms in real deployments.
  • Use lazy loading selectively: defer below-the-fold content and heavy widgets, but keep above-the-fold critical elements eager and stable.
  • Prevent regressions with budgets, bundle analysis, and recurring CWV checks—performance is a product feature, not a one-time task.

# Conclusion#

Website performance optimization is easiest when you treat it as a checklist: measure CWV, fix the LCP element (usually images), cut client-side JavaScript to improve INP, stabilize layouts for CLS, and make caching/CDN behavior explicit.

If you want a hands-on audit and a prioritized optimization plan for your Next.js app—complete with measurable before/after KPIs—Samioda can help: Mobile & Web Development. For teams getting started or migrating, begin with Getting started with Next.js and then apply this checklist to your key templates.

FAQ

Share
A
Adrijan OmičevićSamioda Team
All articles →

Need help with your project?

We build custom solutions using the technologies discussed in this article. Senior team, fixed prices.