DEV Community

Rehan Haider
Rehan Haider

Posted on • Originally published at alirehanhaider.com

Next.js 16 Production SEO Checklist: 12 Things I Check Before Every Deploy

12 Next.js 16 SEO Mistakes I Keep Finding in Production (And How I Fix Them)

Originally published on alirehanhaider.com

Over the past few months, I've audited and debugged several production applications built with Next.js 16 and the App Router.

What's interesting is that most SEO problems weren't caused by missing meta tags or bad keywords. The real issues were architectural decisions that quietly hurt crawling, indexing, Core Web Vitals, and overall search performance.

Many of these applications looked perfectly fine to users, yet search engines were receiving incomplete signals, slow responses, or conflicting metadata.

Here are the 12 most common issues I keep encountering and the fixes that consistently improve performance.


1. Slow Metadata Generation

One of the easiest ways to hurt SEO without realizing it is slowing down metadata generation.

I've seen applications fetch the same database record twice:

  • Once for page content
  • Again inside generateMetadata()

This creates unnecessary work and increases Time To First Byte (TTFB).

A better approach is caching the request so both the page and metadata share the same data source.

import { cache } from "react";

const getProductDetails = cache(async (id: string) => {
  const res = await fetch(`https://api.example.com/products/${id}`, {
    next: { revalidate: 3600 },
  });

  return res.json();
});

export async function generateMetadata({ params }: Props) {
  const { id } = await params;
  const product = await getProductDetails(id);

  return {
    title: "`${product.name} | Shop`,"
    description: "product.summary,"
  };
}
Enter fullscreen mode Exit fullscreen mode

When metadata becomes a bottleneck, crawlers often receive slower responses and incomplete page information.


2. Hydration Errors That Break Content Rendering

Hydration mismatches aren't just a developer experience problem.

I've repeatedly found invalid HTML structures like this:

<p>
  <div>Content</div>
</p>
Enter fullscreen mode Exit fullscreen mode

Browsers automatically correct invalid markup, but React expects the original structure during hydration.

The result?

  • Hydration warnings
  • Broken rendering
  • Missing content
  • Unpredictable crawler behavior

Always use proper container elements instead of nesting block-level elements inside paragraphs.


3. The Robots.txt Staging Trap

This mistake appears surprisingly often.

A staging environment contains:

Disallow: /
Enter fullscreen mode Exit fullscreen mode

The assumption is that search engines won't index those pages.

The reality is more complicated.

If Google cannot crawl the page, it also cannot see your noindex directive. In some situations, URLs can still appear in search results.

Instead, use:

X-Robots-Tag: noindex
Enter fullscreen mode Exit fullscreen mode

at the server level for development and staging environments.


4. Broken XML Sitemaps Reaching Production

Many teams only validate their sitemap after deployment.

By then, search engines may already have discovered malformed XML.

A better strategy is validating sitemap generation during the build process so failures are caught before deployment.

Think of sitemap validation as a test, not a post-launch task.


5. Multiple Canonical Tags

This issue is becoming more common with nested App Router layouts.

A page accidentally renders:

<link rel="canonical" ... />
<link rel="canonical" ... />
Enter fullscreen mode Exit fullscreen mode

Now search engines receive conflicting signals.

Instead of helping rankings, you're creating ambiguity.

Every indexable page should expose exactly one canonical URL.

No exceptions.


6. Font Loading That Causes CLS

I still see many projects loading Google Fonts with traditional <link> tags.

That approach often introduces layout shifts when fonts arrive after content has already rendered.

Using next/font eliminates the extra network request and significantly reduces CLS.

import { Inter } from "next/font/google";

const inter = Inter({
  subsets: ["latin"],
  variable: "--font-inter",
  display: "swap",
  preload: true,
});
Enter fullscreen mode Exit fullscreen mode

Small improvement. Big SEO impact.


7. Misusing Image Priority

I've reviewed pages where almost every image was marked as:

priority
Enter fullscreen mode Exit fullscreen mode

The intention is good.

The outcome is usually worse performance.

When multiple images compete during the critical loading phase, bandwidth gets divided among them.

Instead:

  • Identify the true LCP image
  • Give only that image priority
  • Use AVIF where possible
  • Keep WebP as a fallback
images: {
  formats: ["image/avif", "image/webp"],
  deviceSizes: [640, 750, 828, 1080, 1200, 1920],
}
Enter fullscreen mode Exit fullscreen mode

8. Loading Third-Party Scripts Too Early

Marketing tools, chat widgets, analytics platforms, heatmaps...

Every team wants them.

Few teams measure their cost.

I've seen non-essential scripts add hundreds of milliseconds to Total Blocking Time.

A simple rule:

  • Analytics → afterInteractive
  • Chat widgets → lazyOnload
  • Everything else → defer until needed
<Script
  id="gtm-loader"
  strategy="afterInteractive"
  dangerouslySetInnerHTML={{ __html: gtmScript }}
/>

<Script
  src="https://cdn.livechat.example.com/widget.js"
  strategy="lazyOnload"
/>
Enter fullscreen mode Exit fullscreen mode

9. Dynamic Import Waterfalls

Code splitting is great until it becomes excessive.

I've encountered pages with dozens of tiny dynamic imports.

Each import triggers another request.

Each request adds latency.

On slower networks, the delay becomes noticeable.

Instead of twenty separate chunks, group related components into a single deferred bundle.

Fewer requests often outperform hyper-granular splitting.


10. Missing ISR Revalidation

Some dynamic routes regenerate content on every request.

The result:

  • Increased server workload
  • Slower responses
  • More cold starts
  • Higher infrastructure costs

If content doesn't change every second, use:

export const revalidate = 3600;
Enter fullscreen mode Exit fullscreen mode

Let the edge cache do its job.


11. Staging Environments Accidentally Indexed

This deserves repeating because it causes real problems.

I've seen:

  • Development URLs indexed
  • Preview deployments ranking
  • Duplicate content appearing in search

Relying solely on robots.txt isn't enough.

Always combine staging protection with proper X-Robots-Tag headers.


12. Skipping Lighthouse Testing Before Release

Many teams only monitor real-user metrics after launch.

By then, fixing architectural issues becomes much harder.

Before every production release, I run Lighthouse using a simulated slow 4G connection.

The goal isn't chasing a perfect score.

The goal is finding bottlenecks before users and search engines do.

Here's one example from a recent optimization project:

Metric Before After
Lighthouse Score 68 98
LCP 4.8s 1.9s
CLS 0.23 0.01
TBT 620ms 40ms

Final Thoughts

Most Next.js SEO problems aren't caused by SEO itself.

They're caused by performance bottlenecks, rendering mistakes, caching issues, and architecture decisions that quietly affect how search engines experience your application.

The good news is that fixing these issues usually improves both rankings and user experience at the same time.

If you're building with Next.js 16, start by auditing metadata generation, script loading, image priorities, caching, and indexing controls. Those five areas alone often uncover the biggest opportunities.

What would you add to this list?
Drop your production checks in the comments — always looking to improve this.

Top comments (0)