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
CriticalTypeScript strict mode — no any, no type assertions without comment
CriticalServer Components by default; Client Components only when hooks are needed
CriticalServer 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
CriticalCLS = 0 — explicit width/height on all images, no layout-shifting fonts
CriticalINP under 200ms — heavy client logic moved to Server Components or Web Workers
Criticalnext/image with sizes prop on every image — no raw <img> tags in production
Criticalnext/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
CriticalgenerateStaticParams() for all dynamic routes you want pre-rendered
CriticalJSON-LD schema: Organization/Person on root, BreadcrumbList on every page, Article on posts
CriticalDynamic 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
Criticalfetch() cache: 'force-cache' with revalidate tags — not raw unstable_cache
CriticalrevalidatePath / revalidateTag in Server Actions after mutations
CriticalLoading 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
CriticalCSP headers in next.config — at minimum: no inline scripts outside LD+JSON
CriticalServer-only data access gated by auth check before any DB read
CriticalRate 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
CriticalEnvironment variables scoped to Production / Preview / Development — not shared
CriticalEdge 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.
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.