nextjs-seo

from laguagu/claude-code-nextjs-skills

Claude Code skills for AI apps • Next.js 16 • AI SDK 6 • pgvector • bun • Ralph Loop

6 stars0 forksUpdated Jan 26, 2026
npx skills add https://github.com/laguagu/claude-code-nextjs-skills --skill nextjs-seo

SKILL.md

Next.js SEO Optimization

Comprehensive SEO guide for Next.js 16+ applications using App Router.

Version: Updated for Next.js 16.1.3 (January 2026)

Quick SEO Audit

Run this checklist for any Next.js project:

  1. Check robots.txt: curl https://your-site.com/robots.txt
  2. Check sitemap: curl https://your-site.com/sitemap.xml
  3. Check metadata: View page source, search for <title> and <meta name="description">
  4. Check JSON-LD: View page source, search for application/ld+json
  5. Check Core Web Vitals: Run Lighthouse in Chrome DevTools

Essential Files

app/layout.tsx - Root Metadata

import type { Metadata, Viewport } from 'next';

// Viewport (separate export required in Next.js 14+)
export const viewport: Viewport = {
  width: 'device-width',
  initialScale: 1,
  maximumScale: 5,
  userScalable: true,
  themeColor: [
    { media: '(prefers-color-scheme: light)', color: '#ffffff' },
    { media: '(prefers-color-scheme: dark)', color: '#0a0a0a' },
  ],
};

export const metadata: Metadata = {
  metadataBase: new URL('https://your-site.com'),
  title: {
    default: 'Site Title - Main Keyword',
    template: '%s | Site Name',
  },
  description: 'Compelling description with keywords (150-160 chars)',
  keywords: ['keyword1', 'keyword2', 'keyword3'],
  openGraph: {
    type: 'website',
    locale: 'en_US',
    url: 'https://your-site.com',
    siteName: 'Site Name',
    title: 'Site Title',
    description: 'Description for social sharing',
    images: [{ url: '/og-image.png', width: 1200, height: 630, alt: 'Site preview' }],
  },
  twitter: {
    card: 'summary_large_image',
    title: 'Site Title',
    description: 'Description for Twitter',
    images: ['/og-image.png'],
  },
  alternates: {
    canonical: '/',
  },
  robots: {
    index: true,
    follow: true,
  },
};

app/sitemap.ts - Dynamic Sitemap

import type { MetadataRoute } from 'next';

export default function sitemap(): MetadataRoute.Sitemap {
  const baseUrl = 'https://your-site.com';

  return [
    {
      url: baseUrl,
      lastModified: new Date(),
      changeFrequency: 'weekly',
      priority: 1,
      images: [`${baseUrl}/og-image.png`], // Next.js 16 Image Sitemap
    },
    {
      url: `${baseUrl}/about`,
      lastModified: new Date(),
      changeFrequency: 'monthly',
      priority: 0.8,
    },
  ];
}

app/robots.ts - Robots Configuration

import type { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
  const baseUrl = 'https://your-site.com';

  return {
    rules: [
      {
        userAgent: '*',
        allow: '/',
        disallow: ['/api/', '/_next/', '/admin/'],
      },
    ],
    sitemap: `${baseUrl}/sitemap.xml`,
    host: baseUrl,
  };
}

Key Principles

Rendering Strategy for SEO

StrategyUse WhenSEO Impact
SSG (Static)Content rarely changesBest - pre-rendered HTML
SSRDynamic content per requestGreat - server-rendered
ISRLarge sites, periodic updatesGreat - cached + fresh
CSRDashboards, authenticated areasPoor - avoid for SEO pages

Core Web Vitals Targets

MetricTargetImpact
LCP (Largest Contentful Paint)< 2.5sLoading speed
INP (Interaction to Next Paint)< 200msInteractivity
CLS (Cumulative Layout Shift)< 0.1Visual stability

References

Common Mistakes to Avoid

  1. Mixing next-seo with Metadata API - Use only Metadata API in App Router
  2. Missing canonical URLs - Always set alternates.canonical
  3. Using CSR for SEO pages - Use SSG/SSR for indexable content
  4. Blocking assets in robots.txt - Don't block CSS/JS needed for rendering
  5. Missing metadataBase - Required for relative URLs in metadata
  6. Viewport in metadata - Must be separate export in Next.js 14+
  7. Mixing metadata object and generateMetadata - Use one or the other, not both

Quick Fixes

Add noindex to a page

export const metadata: Metadata = {
  robots: {
    index: false,
    follow: false,
  },
};

Dynamic metadata per page

export async function generateMetadata({ params }): Promise<Metadata> {
  const product = await getProduct(params.id);
  return {
    title: product.name,
    description: product.description,
  };
}

Canonical for dynamic routes

export async function generateMetadata({ params }): Promise<Metadata> {
  r

...
Read full content

Repository Stats

Stars6
Forks0
LicenseMIT License