Performance optimization without measurement is guessing. This guide covers the Core Web Vitals targets you are aiming for, the Next.js-specific optimizations that have the most impact, and the tooling to confirm your changes are working.
Core Web Vitals Targets
Google measures real-user performance using three metrics. For your site to have "good" Core Web Vitals, 75% of real-user sessions must pass all three:
LCP (Largest Contentful Paint) measures how long until the largest visible element is rendered. Target: under 2.5 seconds. Poor: over 4 seconds.
CLS (Cumulative Layout Shift) measures how much the layout shifts during load. Target: under 0.1. Poor: over 0.25.
INP (Interaction to Next Paint) measures how quickly the page responds to user input. Target: under 200 milliseconds. Poor: over 500 milliseconds.
These are not synthetic benchmarks from your fast connection. They are percentiles from real users on real devices and networks. A 75th percentile target means your site must perform well even for users on slower hardware.
Next.js Image Component
The next/image component handles several performance problems automatically:
It serves WebP or AVIF format when the browser supports it, which is typically 30-50% smaller than JPEG for photos. It generates responsive srcset attributes so mobile devices download appropriately sized images. It lazy-loads images below the fold by default, deferring their download. It prevents layout shift by requiring width and height props (or fill with a positioned container), so the browser reserves space before the image loads.
For your LCP image (the hero image or largest above-the-fold element), add priority prop to disable lazy loading and start fetching it immediately. This is one of the highest-impact single changes for LCP improvement.
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority // Above-the-fold hero: always add this
/>
Font Optimization with next/font
Layout shift caused by fonts (FOUT -- Flash of Unstyled Text) is a common CLS problem. When a fallback system font is displayed, then swapped for the web font, the layout shifts.
next/font solves this by: hosting fonts on your own domain (no cross-origin DNS lookup), generating an optimized font-display CSS automatically, and using size-adjust to make the fallback font match the web font dimensions closely enough to eliminate or minimize the shift.
import { Inter } from "next/font/google";
const inter = Inter({
subsets: ["latin"],
display: "swap",
});
No manual font download, no <link rel="preload">, no font-face declarations. One import handles it all.
Link Prefetching
Next.js prefetches linked pages automatically when a <Link> enters the viewport. On a content-heavy page with many links, this can cause a flood of prefetch requests on mobile, consuming data the user did not ask for.
For links that are rarely clicked (footer links, secondary navigation), consider disabling prefetching:
<Link href="/rarely-visited" prefetch={false}>
Terms of Service
</Link>
For frequently clicked links, keep prefetching on. The goal is to be selective, not to disable it everywhere.
Dynamic Imports for Code Splitting
Next.js splits code at the route level automatically. For large components that are not needed immediately (a rich text editor, a date picker library, a chart library), dynamic imports split them further:
import dynamic from "next/dynamic";
const HeavyEditor = dynamic(() => import("@/components/HeavyEditor"), {
loading: () => <Skeleton />,
ssr: false, // If it uses browser APIs
});
This defers the JavaScript download until the component is actually rendered. For components with large dependencies (Monaco Editor is 2MB+, for example), this has major impact on initial load.
Server-Side Performance
Avoid the N+1 query problem. Fetching a list of items and then making a separate database query for each item's related data is the N+1 problem. Fetch related data in bulk with $in queries or use $lookup aggregations.
Minimize data returned from database queries. Use projection to return only the fields you need. Returning entire documents when you only need three fields wastes bandwidth and memory on every request.
Use indexes. A query on an unindexed field does a full collection scan. Add indexes for fields you filter and sort on. MongoDB's explain() method shows whether a query is using an index.
Reduce cold starts. For serverless deployments, keep Lambda/Edge function bundle sizes small. Large node_modules slow cold starts. Check what you are actually importing.
Bundle Analysis
@next/bundle-analyzer shows you what is in your JavaScript bundles. After adding it to your Next.js config:
ANALYZE=true pnpm build
A visual treemap opens in your browser. Look for:
Large dependencies that could be replaced with smaller alternatives. Libraries being bundled multiple times (deduplication issues). Large libraries included for small utilities (importing all of lodash for one function).
Common finds: moment.js (replace with date-fns or dayjs), lodash (use native equivalents or cherry-pick imports), large icon libraries (import individual icons instead of the entire set).
Measurement Tooling
Chrome DevTools Performance tab for profiling specific interactions. The flame chart shows long JavaScript tasks that cause INP problems.
PageSpeed Insights gives you field data (real users) alongside lab data. The field data is what Google uses for search ranking. Lab data alone is not sufficient.
Lighthouse CI runs Lighthouse in your CI pipeline on every pull request. Set score thresholds to catch regressions before they reach production.
Vercel Analytics gives you real Core Web Vitals data broken down by page and device. If you are deployed on Vercel, this is the clearest view of real-user performance.
Google Search Console Core Web Vitals report shows which pages are failing in field data, grouped by issue type. This is where you find out which pages are actually causing search ranking problems.
The measurement loop: check Search Console for failing pages, profile the specific issue in DevTools, make the fix, verify in PageSpeed Insights, confirm improvement in Search Console over the next 28-day data window.
Keep Reading
- Core Web Vitals in 2026: What They Are and How to Actually Pass -- deeper dive into each metric and its causes
- Next.js App Router Patterns in 2026: What to Use and What to Avoid -- rendering patterns that affect performance
- Next.js Caching in 2026: The Complete Guide to All Four Layers -- caching as a performance tool
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace -- chat, projects, time tracking, AI meeting summaries, and invoicing -- in one tool. Try it free.