📈 Next.js SEO — A Clean & Practical Checklist
By Achintya Tiwari

📈 Next.js SEO — A Clean & Practical Checklist

TechnologyTechnologyProductivity

If you want your Next.js site to actually show up on Google (and look great when shared on social), this is what you should do — step by step.


🏷️ Meta Tags — Why They Matter

Meta tags give search engines and social platforms info about your page.

If you skip them, your site might look like a blank page on Google or Twitter.

👉 Always add these basic meta tags:

TagWhy it's important
titleThe title of your page (what people see on Google results)
descriptionShort description (also visible in search results)
keywordsOptional, not used much by Google, but harmless
robotsTells crawlers if they should index your page
viewportControls how your site looks on mobile devices
charSetCharacter encoding (UTF-8 is standard)

👉 Open Graph meta tags: (for social sharing)

TagWhy it's important
og:site_nameName of your site
og:localeLanguage/locale
og:titleTitle when shared on social
og:descriptionDescription on social
og:typewebsite or article
og:urlURL of the page
og:imageImage shown in preview (use PNG/JPG — no WebP!)
og:image:altAlt text for accessibility
og:image:typeImage type (image/png)
og:image:width + og:image:heightImage dimensions

👉 Article-specific Open Graph tags:

(important for blog posts, articles, news)

TagWhy it's important
article:published_timeWhen it was published
article:modified_timeLast update time
article:authorAuthor name

👉 Twitter meta tags: (for Twitter/X previews)

TagWhy it's important
twitter:cardLarge image summary
twitter:siteSite's Twitter handle
twitter:creatorAuthor's Twitter handle
twitter:titleTitle on Twitter
twitter:descriptionDescription on Twitter
twitter:imageImage URL (again PNG/JPG)

⚙️ How to Add Meta Tags in Next.js

👉 In App Router, define viewport + metadata:

export const viewport = { width: "device-width", initialScale: 1, themeColor: "#ffffff" };
export const metadata = { title: "Site Title", description: "Short site description", keywords: ["keyword1", "keyword2"], openGraph: { siteName: "My Site", type: "website", locale: "en_US", images: [{ url: "https://yoursite.com/og-image.png", width: 1200, height: 630, alt: "My Site" }] }, twitter: { card: "summary_large_image", title: "Site Title", description: "Short site description", images: [{ url: "https://yoursite.com/og-image.png", width: 1200, height: 630, alt: "My Site" }] }, robots: { index: true, follow: true, googleBot: "index, follow" }, alternates: { canonical: "https://yoursite.com" } };

👉 On dynamic pages (blog posts), use generateMetadata():

export async function generateMetadata({ params }) { const post = await fetch(`YOUR_ENDPOINT/${params.slug}`).then(res => res.json()); return { title: `${post.title} | My Site`, description: post.description, openGraph: { title: `${post.title} | My Site`, description: post.description, type: "article", url: `https://yoursite.com/${post.slug}`, publishedTime: post.created_at, modifiedTime: post.modified_at, authors: ["https://yoursite.com/about"], tags: post.categories, images: [ { url: `https://yoursite.com/assets/${post.slug}/thumbnail.png`, width: 1024, height: 576, alt: post.title } ] }, twitter: { card: "summary_large_image", title: `${post.title} | My Site`, description: post.description, images: [{ url: `https://yoursite.com/assets/${post.slug}/thumbnail.png`, width: 1024, height: 576, alt: post.title }] }, alternates: { canonical: `https://yoursite.com/${post.slug}` } }; }

📜 JSON-LD Schema — Why Bother?

JSON-LD adds "structured data" for Google.

It helps Google understand your page type (Blog Post, Product, Event...) and improves rich snippets.

👉 Example for blog post:

const jsonLd = { "@context": "https://schema.org", "@type": "BlogPosting", mainEntityOfPage: { "@type": "WebPage", "@id": "https://yoursite.com/my-post" }, headline: "Post Title", description: "Post description", image: "https://yoursite.com/assets/my-post/thumbnail.png", datePublished: "2024-01-11T11:35:00+07:00", dateModified: "2024-01-11T11:35:00+07:00", author: { "@type": "Person", name: "Your Name", url: "https://linkedin.com/in/yourname" }, publisher: { "@type": "Person", name: "Your Name", logo: { "@type": "ImageObject", url: "https://yoursite.com/avatar.jpg" } }, inLanguage: "en-US", isFamilyFriendly: "true" };

👉 Render this in your component:

<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />

👉 Use this tool to generate schemas: https://technicalseo.com/tools/schema-markup-generator/


🗺️ Sitemap — Why You Need It

Sitemap helps Google crawl all your pages. Without it, some deep links may never get indexed.

👉 In Pages Router:

Use next-sitemap

npm install next-sitemap npx next-sitemap

👉 In App Router:

Manually define app/sitemap.ts:

export default async function sitemap() { const pages = [ { url: "https://yoursite.com", lastModified: new Date(), changeFrequency: "daily", priority: 1 }, { url: "https://yoursite.com/about", lastModified: new Date(), changeFrequency: "monthly", priority: 0.9 } // more pages ]; return pages; }

👉 Result will be accessible at:

arduino CopyEdit https://yoursite.com/sitemap.xml

🤖 robots.txt — Controlling Crawlers

robots.txt tells search engines which pages to crawl or ignore.

👉 In Pages Router:

public/robots.txt:

makefile CopyEdit User-agent: * Disallow: Sitemap: https://yoursite.com/sitemap.xml

👉 To block certain pages:

Disallow: /search?q= Disallow: /admin

👉 In App Router:

Define app/robots.ts:

export default function robots() { return { rules: { userAgent: "*", allow: ["/"], disallow: ["/search?q=", "/admin"] }, sitemap: ["https://yoursite.com/sitemap.xml"] }; }

🔗 Important Link Tags

👉 Always include these in your head:

Link TagPurpose
canonicalPrevent duplicate content issues — tell Google the "main" URL
alternateUsed for multilingual sites
iconFavicon
apple-touch-iconiOS home screen icon
manifestFor PWA support

Summary — What You Should Do (Minimal Checklist)

✅ Add full Meta Tags (title, description, OG, Twitter)

✅ Add JSON-LD schema for key pages

✅ Generate and serve a sitemap.xml

✅ Serve a robots.txt

✅ Include proper link tags (canonical, icon, manifest)


If you do all of this, your Next.js site will:

✅ Look great in search results

✅ Show rich previews on social media

✅ Be fully crawlable and indexable by Google