Developer Guide · Updated May 2026

Production Next.js 2026

Architecture, performance, SEO, and deployment. Everything that separates an app that ships and ranks from one that works in dev and collapses in production.

95+

Lighthouse floor

< 2.5s

LCP target

0

CLS target

< 200ms

INP target

Production Checklist

Ship Confidently — Check Every Box

These aren't opinions. They're the difference between a Next.js app that works in a demo and one that stays up, ranks, and scales with real users.

Architecture

App Router with colocated layouts, loading.tsx, and error.tsx per segment

Critical

TypeScript strict mode — no any, no type assertions without comment

Critical

Server Components by default; Client Components only when hooks are needed

Critical

Server Actions for mutations — no separate API routes for internal calls

Parallel Routes for modals and dashboards that need independent loading states

Route groups to share layouts without polluting URL structure

Performance

LCP under 2.5s — hero image preloaded, above-the-fold CSS inlined

Critical

CLS = 0 — explicit width/height on all images, no layout-shifting fonts

Critical

INP under 200ms — heavy client logic moved to Server Components or Web Workers

Critical

next/image with sizes prop on every image — no raw <img> tags in production

Critical

next/font for all custom fonts — no Google Fonts CDN link in layout.tsx

Dynamic imports for heavy client-side libraries (charts, editors, maps)

SEO

generateMetadata() on every page — unique title, description, and canonical URL

Critical

generateStaticParams() for all dynamic routes you want pre-rendered

Critical

JSON-LD schema: Organization/Person on root, BreadcrumbList on every page, Article on posts

Critical

Dynamic OG images via opengraph-image.tsx — not a single generic image for all pages

robots.ts and sitemap.ts in app/ root — auto-generated, revalidated with pages

hreflang tags if targeting multiple languages or regions

Data & Caching

ISR (revalidate) for pages that change on a schedule — not all pages need real-time

Critical

fetch() cache: 'force-cache' with revalidate tags — not raw unstable_cache

Critical

revalidatePath / revalidateTag in Server Actions after mutations

Critical

Loading skeletons via loading.tsx — never leave a blank page while data loads

Suspense boundaries around async Server Components with specific fallbacks

Security & Config

Environment variables: NEXT_PUBLIC_ only for truly public values — never API keys

Critical

CSP headers in next.config — at minimum: no inline scripts outside LD+JSON

Critical

Server-only data access gated by auth check before any DB read

Critical

Rate limiting on public API routes — Next.js Route Handlers are wide open by default

vercel.json: no debug headers, no x-powered-by in prod

Deployment (Vercel)

Preview deployments on every PR — not merging unreviewed code to main

Critical

Environment variables scoped to Production / Preview / Development — not shared

Critical

Edge Config or Vercel KV for feature flags and A/B tests — not env var redeploys

Vercel Analytics + Speed Insights on every production deployment

Custom domains with HSTS and automatic HTTPS — Vercel handles this by default

Common Mistakes

The App Router Footguns Nobody Warns You About

These mistakes are invisible in development, obvious in production, and show up in every Next.js codebase I've audited.

"use client" at the top of every file

This turns your Server Components back into client bundles — the exact problem App Router was designed to solve. Add it only to the file that actually needs useState, useEffect, or event handlers.

Fetching in useEffect instead of Server Components

Data that doesn't change on user interaction belongs in an async Server Component, not a client-side fetch. useEffect fetches create waterfalls, flash blank states, and aren't cached by Next.js.

Skipping generateStaticParams for dynamic routes

Without generateStaticParams, Next.js renders dynamic routes on-demand with no prebuilt HTML. Every visitor hits cold rendering and waits. List every slug you know at build time.

One revalidate value for every page

A blog post that changes once a month doesn't need revalidate: 60. A dashboard probably shouldn't use ISR at all. Match your revalidation strategy to how often the data actually changes.

Missing sizes on next/image with fill or responsive layout

Without the sizes prop, Next.js downloads the full-resolution image at every viewport. This alone can cost 500KB–2MB on mobile — and tanks your Lighthouse score.

No canonical URLs on dynamically generated pages

If the same content is reachable at multiple URLs (with query params, trailing slashes, or case variants), Google splits link equity between them. Every page needs an explicit alternates.canonical.

Common Questions

Next.js Production FAQ

The questions that come up on every project — answered directly.

Should I use the App Router or Pages Router for a new project in 2026?

App Router for any new project. It's been stable since Next.js 13.4, and Next.js 15/16 invest entirely in it. Pages Router still works, but Server Components, Suspense, and the caching model are App Router-only. If you're on Pages Router and it's working, no need to migrate immediately — but new projects should start with App Router.

How do I get 95+ Lighthouse without compromising features?

Most Lighthouse regressions come from three things: unoptimised images (LCP), layout shift from fonts or async components (CLS), and heavy client-side JavaScript (INP + TBT). Use next/image with explicit dimensions, next/font for typography, and move data fetching to Server Components. Remaining regressions are almost always caused by third-party scripts — load them with next/script's lazyOnload strategy.

What's the right caching strategy for Next.js in 2026?

Default is aggressive — Next.js 15 changed fetch() to no-store by default for Server Components in dynamic rendering contexts. For data that changes on a schedule, use export const revalidate = N at the segment level. For pages triggered by mutations, combine revalidatePath/revalidateTag with Server Actions. Avoid unstable_cache directly — use the fetch() abstraction or React's cache() instead.

How should I structure TypeScript in a large Next.js codebase?

TypeScript strict: true in tsconfig — no exceptions. Put global types in types/index.ts, not global.d.ts. Co-locate component prop types with the component, not in a separate types file. Use satisfies instead of type assertions. Avoid Zod in Server Components unless you're actually validating untrusted input — TypeScript + strict generics is enough for internal data shapes.

What structured data does every Next.js site need?

At minimum: Person or Organization on the root layout (sitewide authority), BreadcrumbList on every page (navigation signal), WebPage or Article on content pages. If you have FAQs, add FAQPage. If you're a service business, add Service with offers. If you have ratings, add AggregateRating. Use JSON-LD (script type='application/ld+json') — never RDFa or Microdata in a React codebase.

When should I use Server Actions vs Route Handlers?

Server Actions for mutations triggered from forms or client components in your own UI — they're colocated, type-safe, and revalidate cache automatically. Route Handlers for public APIs, webhooks, or endpoints consumed by third parties who can't call a Server Action. Never expose a Route Handler that calls a Server Action internally — pick one.

Available for Next.js projects

Need someone to build this right the first time?

I apply every item on this checklist to every project I take on. If you want a Next.js app that ships fast, ranks, and stays up — let's talk.

Hire a Next.js Developer