Skip to content
SEOSpot

Platforms · Next.js

We built our own site on Next.js. Most SEO agencies haven't. When you're shipping React for performance, your SEO partner should ship React too.

SEO for Next.js sites — App Router and Pages Router. We work with engineering teams shipping React-based marketing sites, web applications, and content platforms. Server-rendered schema, programmatic SEO at scale, Core Web Vitals optimization, and AI engine citation done in code, not in dashboards.

Next.js at a glance

Typical buyer
SaaS, B2B tech, developer-focused brands
Rendering modes
SSR, SSG, ISR, RSC
SEO foundation
Excellent — when used correctly
Our own stack
Yes — this site is Next.js 16

The problem

Next.js gives you SEO superpowers and confuses most agencies into ignoring them.

Next.js produces some of the fastest, most SEO-friendly sites on the modern web — when used correctly. Server-rendered content, near-instant TTFB on edge runtimes, granular metadata APIs, programmatic routes for SEO at scale, and clean structured data via React components. Most SEO agencies don't understand any of it. They treat Next.js like a black box and add WordPress-shaped recommendations that don't apply. The teams winning Next.js SEO in 2026 work with partners who can read the code, ship the schema components, and review the PRs alongside their engineering team.

Platform-specific gotchas

The Next.js traps we fix on every engagement

These are the issues we find on most Next.js sites — including ones that previously hired SEO agencies. If your site has these, fixing them is usually the highest-leverage technical work available.

01

Client components hiding content from crawlers

The problem

React Server Components ship rendered HTML to the client. Client components render in the browser. AI crawlers (and sometimes Googlebot) don't always execute the JavaScript, so any 'use client' content that loads dynamically becomes invisible.

The fix

Server-render content that matters for SEO. Use client components only for interactivity (forms, animations, dropdowns). Static content, headings, body copy, and critical CTAs should be server components. Verify with View Source — if your H1 isn't in the initial HTML, it's likely invisible to crawlers.

Bad: SEO-critical content in a client component

'use client';
  import { useState, useEffect } from 'react';
  
  export default function ProductPage({ slug }: { slug: string }) {
    const [product, setProduct] = useState(null);
  
    useEffect(() => {
      fetch(`/api/products/${slug}`).then(r => r.json()).then(setProduct);
    }, [slug]);
  
    if (!product) return <div>Loading...</div>;
    // ❌ This H1 isn't in the initial HTML — crawlers may miss it
    return <h1>{product.name}</h1>;
  }
02

Metadata API misconfiguration

The problem

Next.js's metadata API (App Router) is powerful but easy to misuse. Common mistakes: forgetting metadataBase, generating wrong canonical URLs, using static metadata where dynamic is needed, and missing OG image sizing.

The fix

Set metadataBase in the root layout. Use generateMetadata() for any page where title/description varies. Always include canonical, OpenGraph (with absolute image URL), and Twitter card. Validate with the Twitter Card Validator and Facebook Sharing Debugger after deploy.

app/layout.tsx — proper metadata base setup

import type { Metadata } from 'next';
  
  export const metadata: Metadata = {
    metadataBase: new URL('https://theseospot.com'),
    title: {
      default: 'SEOSpot — SEO + Link Building',
      template: '%s | SEOSpot',
    },
    description: 'SEO and link building for B2B, SaaS, and ecommerce brands.',
    openGraph: {
      type: 'website',
      siteName: 'SEOSpot',
      images: ['/og-default.png'], // resolved against metadataBase
    },
    twitter: { card: 'summary_large_image' },
  };
03

Schema as React components vs raw JSON-LD

The problem

Some Next.js sites build schema as React components that interpolate badly, especially when content includes quotes, line breaks, or special characters. The schema renders but Google parses it as invalid.

The fix

Generate schema as plain JSON objects in TypeScript, then render via a single JsonLd component using dangerouslySetInnerHTML with JSON.stringify. This avoids React's JSX escaping issues and produces valid JSON-LD every time.

components/JsonLd.tsx — clean schema rendering

interface JsonLdProps {
    data: object | object[];
  }
  
  export function JsonLd({ data }: JsonLdProps) {
    return (
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
      />
    );
  }
  
  // Usage in a page:
  // <JsonLd data={articleSchema({ headline, datePublished, ... })} />
04

Sitemap and robots.txt not generated correctly

The problem

Hand-built sitemaps go stale immediately. Static robots.txt files don't differentiate between environments. Next.js teams often skip both because they're 'one more thing.'

The fix

Use Next.js's built-in sitemap.ts and robots.ts conventions. Generate sitemap programmatically from your content registries (services, blog posts, etc.). Generate robots dynamically based on environment so production allows crawling and preview/staging blocks it.

05

Edge runtime breaking schema injection

The problem

Some Next.js apps run on the Edge Runtime for performance. Edge runtime has Web API restrictions that can break certain server-side schema generation patterns, especially anything using Node.js modules.

The fix

Keep schema generation in pure JS/TS using Web APIs only. If you need Node-specific functionality, opt those routes back to the Node runtime. Most schema generation works fine on Edge if you avoid Node-only libraries.

06

Image optimization not configured

The problem

Teams use raw <img> tags or misconfigure next/image. Result: huge unoptimized images, no responsive srcset, no lazy loading, terrible LCP scores. Or worse — images optimized through next/image but with priority={false} on hero images, causing slow LCP.

The fix

Use next/image for every image. Set priority on above-the-fold hero images. Configure remotePatterns in next.config for any external image domains. Pre-define image sizes and use responsive sizes prop. Audit LCP after launch.

Proper next/image usage for above-the-fold images

import Image from 'next/image';
  
  export default function Hero() {
    return (
      <section>
        <h1>Headline</h1>
        <Image
          src="/hero.jpg"
          alt="Descriptive alt text"
          width={1920}
          height={1080}
          priority // ✓ critical for LCP on hero images
          sizes="100vw"
          quality={85}
        />
      </section>
    );
  }
07

ISR revalidation timing wrong for SEO

The problem

Incremental Static Regeneration is powerful but teams often set revalidate too short (every minute) or too long (once a day for daily-updating content). Either extreme creates SEO friction — too short wastes resources; too long serves stale content.

The fix

Match revalidate windows to actual content update frequency. Marketing pages: revalidate weekly or use on-demand revalidation. Blog: daily or on-demand. E-commerce products: hourly or on-demand. Use revalidateTag() or revalidatePath() on actual content changes rather than time-based intervals.

Next.js tools we use (and avoid)

Our opinionated Next.js stack

We're skeptical of agencies that recommend whatever's affiliate-friendly. Here's what we actually install on Next.js engagements — and what we tell clients to remove.

Next.js built-in metadata + sitemap + robots APIs

We recommend

Native metadata, sitemap generation, and robots.txt — no plugins needed.

Built-in

Use these fully. The metadata API is more flexible than any WordPress SEO plugin. Sitemap and robots conventions integrate with the build. Zero dependencies, zero overhead.

next-seo (npm package)

Use with care

Higher-level SEO component library for Next.js — popular for Pages Router.

Free

Useful on Pages Router projects where the metadata API doesn't exist. For App Router, the native metadata API is better. Don't add this to an App Router project — it's redundant.

@vercel/analytics + Speed Insights

We recommend

Real-user performance monitoring including Core Web Vitals.

Freemium

Lightweight, integrates natively with Vercel deployments. Useful for monitoring INP, LCP, CLS over time. Lazy-loads automatically.

Schema.org type packages (schema-dts)

We recommend

TypeScript types for schema.org JSON-LD.

Free

Helpful for catching schema errors at build time. We use it in our own schema generators for type safety.

Schema implementation

Structured data done correctly on Next.js

Schema is one of the highest-leverage technical investments for AI engine citation. Here's how we implement each type on Next.js.

Organization (root layout)

schema.org/Organization (root layout)

Why it matters

Brand entity signals on every page for Knowledge Graph and AI citation.

How we implement it

Generate once in app/layout.tsx, inject via JsonLd component. Uses TypeScript helpers for type safety.

// lib/schema.ts
  export function organizationSchema() {
    return {
      '@context': 'https://schema.org',
      '@type': 'Organization',
      name: 'SEOSpot',
      url: 'https://theseospot.com',
      logo: 'https://theseospot.com/logo.png',
      sameAs: [
        'https://twitter.com/seospot',
        'https://linkedin.com/company/seospot',
      ],
    };
  }
  
  // app/layout.tsx
  import { JsonLd } from '@/components/JsonLd';
  import { organizationSchema } from '@/lib/schema';
  
  export default function RootLayout({ children }: { children: React.ReactNode }) {
    return (
      <html lang="en">
        <body>
          <JsonLd data={organizationSchema()} />
          {children}
        </body>
      </html>
    );
  }

Article (dynamic route)

schema.org/Article (dynamic route)

Why it matters

Blog post and content article rich results, AI engine citation.

How we implement it

Generate per-page in generateMetadata or directly in the page component. Pull dates and author from the content source (MDX frontmatter, CMS API, etc.).

BreadcrumbList

schema.org/BreadcrumbList

Why it matters

Breadcrumb rich results.

How we implement it

Build a helper that takes the route path and generates BreadcrumbList from a nav config. Render once per page via JsonLd.

Service / Product (programmatic SEO)

schema.org/Service / Product (programmatic SEO)

Why it matters

Service or product pages at scale with consistent schema.

How we implement it

Generate from a TypeScript registry file. The same registry that drives the route generation also feeds the schema, ensuring perfect alignment.

Combined @graph

schema.org/Combined @graph

Why it matters

Multiple schemas on one page, grouped for cleaner output.

How we implement it

Helper that takes multiple schema objects and combines them under a single @graph property. Renders as one JSON-LD script.

What you get

Deliverables on a Next.js engagement

Next.js technical audit

Rendering strategy (SSR/SSG/ISR/RSC), metadata config, schema generation, image handling, and Core Web Vitals reviewed.

Schema generator library

TypeScript module with generators for every schema type your site needs. Type-safe, testable, reusable across routes.

Metadata + sitemap + robots setup

Full metadata API configuration, programmatic sitemap.ts, environment-aware robots.ts.

Programmatic SEO build

Dynamic routes for comparison pages, integration pages, or content at scale — driven by your data layer.

Core Web Vitals optimization

next/image configuration, font loading, lazy loading strategy, third-party script handling.

Code review partnership

Ongoing PR reviews with your engineering team — we review SEO-affecting changes before they ship.

Common questions

About Next.js SEO

Do you actually know Next.js, or are you a generalist agency?

We use Next.js for our own site (this one) and have built SEO engagements around it for clients. We read TypeScript, ship PRs, review code, and work alongside engineering teams. If you ask us about App Router vs Pages Router, RSC behavior, ISR vs SSG trade-offs, or schema generators in TS, you'll get specific answers, not handwaving.

Will you work with our engineering team or hand them PDF recommendations?

We work with the team. Most Next.js engagements involve us writing TypeScript modules (schema generators, metadata helpers, sitemap logic), submitting PRs, and reviewing engineering PRs that affect SEO. Generic recommendations don't ship on a Next.js codebase — code does.

Can you do programmatic SEO on Next.js?

Yes — programmatic SEO is one of Next.js's strongest use cases. We've built dynamic route patterns generating thousands of pages from TypeScript data files: comparison pages, integration pages, city-specific landing pages, glossary terms. The combination of generateStaticParams, ISR for updates, and clean schema generation makes Next.js arguably the best platform for programmatic SEO at scale.

Do you handle App Router and Pages Router both?

Yes, though our recommendation for new projects is always App Router. Pages Router still has long-term support but App Router is where Vercel's investment is going. For existing Pages Router sites, we work in-place and can plan a gradual migration if it makes sense. We don't push migrations for their own sake — only when the value justifies the disruption.

What about headless CMS on Next.js — Contentful, Sanity, MDX?

All work well for SEO with the right setup. MDX is great for technical content and gives full React component access in posts. Sanity and Contentful work well for editorial teams. We work with whichever is in place; for new builds, we recommend based on team composition (technical → MDX, editorial → Sanity or Contentful, hybrid → Sanity).

What's your refund policy for Next.js engagements?

Same as every engagement — 90-day refund promise. If Google Search Console doesn't show clear upward traffic by day 90, we refund in full. For greenfield Next.js builds without an existing baseline, we adjust the metric to leading indicators (indexed pages, ranking term breadth, Core Web Vitals) since absolute traffic from zero isn't a useful signal yet.

Send me your Next.js site. I'll tell you honestly what's broken.

A 45-minute call where I look at your Next.js site live and tell you what I'd prioritize. If we're a fit, we'll talk about working together. If not, I'll point you to who I'd hire instead.

Book a 45-minute call

Free · 45 min · No obligation