SEO for Next.js 2026: Rank on Google, Appear in AI Search, and Google Discover
Advertisement
SEO for Next.js 2026: Rank Everywhere
SEO in 2026 means three battlefields: Google Search, Google Discover, and AI engines (ChatGPT, Perplexity, Gemini). This guide covers all three.
- Metadata API (Next.js 15)
- Dynamic Metadata for Blog Posts
- JSON-LD Structured Data
- Sitemap
- Robots.txt
- Google Discover Optimization
- AI Engine Optimization
- Internal Linking Strategy
Metadata API (Next.js 15)
// app/layout.tsx — site-wide defaults
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://webcoderspeed.com'),
title: {
default: 'WebCoderSpeed — Master Programming & AI',
template: '%s | WebCoderSpeed',
},
description: 'Master DSA, AI, web development and system design. Daily tutorials on Python, JavaScript, React, Next.js, LLMs, and FAANG interview prep.',
keywords: ['programming', 'DSA', 'AI', 'Next.js', 'React', 'Python', 'LLM'],
authors: [{ name: 'Sanjeev Sharma', url: 'https://webcoderspeed.com' }],
openGraph: {
type: 'website',
siteName: 'WebCoderSpeed',
locale: 'en_US',
images: [{ url: '/og-image.png', width: 1200, height: 630 }],
},
twitter: {
card: 'summary_large_image',
site: '@webcoderspeed',
creator: '@webcoderspeed',
},
robots: {
index: true,
follow: true,
googleBot: { index: true, follow: true, 'max-image-preview': 'large' },
},
alternates: { canonical: 'https://webcoderspeed.com' },
}
Dynamic Metadata for Blog Posts
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next'
import { getPost } from '@/lib/posts'
export async function generateMetadata(
{ params }: { params: { slug: string } }
): Promise<Metadata> {
const post = await getPost(params.slug)
if (!post) return { title: 'Post Not Found' }
const url = `https://webcoderspeed.com/blog/${params.slug}`
return {
title: post.title,
description: post.summary,
keywords: post.tags,
openGraph: {
type: 'article',
title: post.title,
description: post.summary,
url,
images: [
{
url: post.image || '/og-default.png',
width: 1200,
height: 630,
alt: post.title,
},
],
publishedTime: post.date,
authors: ['https://webcoderspeed.com/about'],
tags: post.tags,
},
alternates: { canonical: url },
}
}
JSON-LD Structured Data
Structured data helps Google understand your content AND helps AI engines cite you accurately:
// components/article-schema.tsx
export function ArticleSchema({ post }: { post: Post }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'TechArticle',
headline: post.title,
description: post.summary,
image: `https://webcoderspeed.com${post.image || '/og-default.png'}`,
datePublished: post.date,
dateModified: post.updatedAt || post.date,
author: {
'@type': 'Person',
name: 'Sanjeev Sharma',
url: 'https://webcoderspeed.com/about',
},
publisher: {
'@type': 'Organization',
name: 'WebCoderSpeed',
logo: {
'@type': 'ImageObject',
url: 'https://webcoderspeed.com/logo.png',
},
},
mainEntityOfPage: { '@type': 'WebPage', '@id': `https://webcoderspeed.com/blog/${post.slug}` },
keywords: post.tags.join(', '),
articleSection: post.category,
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}
// BreadcrumbList
export function BreadcrumbSchema({ items }: { items: { name: string; url: string }[] }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
}
return <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }} />
}
// FAQ Schema (gets rich snippets in search)
export function FAQSchema({ questions }: { questions: { q: string; a: string }[] }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: questions.map(({ q, a }) => ({
'@type': 'Question',
name: q,
acceptedAnswer: { '@type': 'Answer', text: a },
})),
}
return <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }} />
}
Sitemap
// app/sitemap.ts
import type { MetadataRoute } from 'next'
import { getAllPosts } from '@/lib/posts'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getAllPosts()
const baseUrl = 'https://webcoderspeed.com'
const staticRoutes: MetadataRoute.Sitemap = [
{ url: baseUrl, lastModified: new Date(), changeFrequency: 'daily', priority: 1 },
{ url: `${baseUrl}/blog`, lastModified: new Date(), changeFrequency: 'daily', priority: 0.9 },
{ url: `${baseUrl}/about`, changeFrequency: 'monthly', priority: 0.5 },
]
const postRoutes: MetadataRoute.Sitemap = posts.map(post => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: new Date(post.date),
changeFrequency: 'monthly',
priority: 0.8,
}))
return [...staticRoutes, ...postRoutes]
}
Robots.txt
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/_next/'],
},
// Allow AI crawlers explicitly
{ userAgent: 'GPTBot', allow: '/' },
{ userAgent: 'ClaudeBot', allow: '/' },
{ userAgent: 'PerplexityBot', allow: '/' },
{ userAgent: 'GoogleBot', allow: '/' },
],
sitemap: 'https://webcoderspeed.com/sitemap.xml',
host: 'https://webcoderspeed.com',
}
}
Google Discover Optimization
Google Discover shows content without searching. To appear:
- Large featured image — minimum 1200px wide,
max-image-preview: large - Fresh content — publish frequently with today's date
- Compelling title — not clickbait but genuinely interesting
- E-E-A-T signals — Experience, Expertise, Authority, Trust
- Fast page — LCP < 2.5s, CLS < 0.1, INP < 200ms
// Ensure Discover eligibility in metadata
export const metadata: Metadata = {
robots: {
googleBot: {
'max-image-preview': 'large', // Required for Discover
'max-snippet': -1,
'max-video-preview': -1,
},
},
}
AI Engine Optimization
For Perplexity, ChatGPT, and Gemini to cite your content:
1. Write definitively — "X is Y" not "X might be Y"
2. Use clear headings — AI extracts structured sections
3. Include code examples — AI engines love citing working code
4. Add FAQ sections — exactly what AI extracts for answers
5. Be comprehensive — AI engines prefer complete, authoritative content
6. Allow crawling — GPTBot, ClaudeBot, PerplexityBot in robots.txt
7. Use structured data — JSON-LD helps AI understand context
Internal Linking Strategy
// Automatic related posts component
async function RelatedPosts({ tags, currentSlug }: { tags: string[]; currentSlug: string }) {
const related = await getAllPosts()
.then(posts => posts
.filter(p => p.slug !== currentSlug && p.tags.some(t => tags.includes(t)))
.sort((a, b) => {
const aScore = a.tags.filter(t => tags.includes(t)).length
const bScore = b.tags.filter(t => tags.includes(t)).length
return bScore - aScore
})
.slice(0, 3)
)
return (
<section>
<h3>Related Articles</h3>
{related.map(post => (
<a key={post.slug} href={`/blog/${post.slug}`}>{post.title}</a>
))}
</section>
)
}
SEO is a compound investment. Every post you publish, every schema you add, every internal link you create — it compounds. Start today, stay consistent.
Advertisement