5 min read927 words

πŸ“ˆ Next.js SEO β€” A Clean & Practical Checklist

Technology
Technology
Productivity

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
title
The title of your page (what people see on Google results)
description
Short description (also visible in search results)
keywords
Optional, not used much by Google, but harmless
robots
Tells crawlers if they should index your page
viewport
Controls how your site looks on mobile devices
charSet
Character encoding (UTF-8 is standard)

πŸ‘‰ Open Graph meta tags: (for social sharing)

TagWhy it's important
og:site_name
Name of your site
og:locale
Language/locale
og:title
Title when shared on social
og:description
Description on social
og:type
website
or
article
og:url
URL of the page
og:image
Image shown in preview (use PNG/JPG β€” no WebP!)
og:image:alt
Alt text for accessibility
og:image:type
Image type (image/png)
og:image:width
+
og:image:height
Image dimensions

πŸ‘‰ Article-specific Open Graph tags:

(important for blog posts, articles, news)

TagWhy it's important
article:published_time
When it was published
article:modified_time
Last update time
article:author
Author name

πŸ‘‰ Twitter meta tags: (for Twitter/X previews)

TagWhy it's important
twitter:card
Large image summary
twitter:site
Site's Twitter handle
twitter:creator
Author's Twitter handle
twitter:title
Title on Twitter
twitter:description
Description on Twitter
twitter:image
Image 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

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
canonical
Prevent duplicate content issues β€” tell Google the "main" URL
alternate
Used for multilingual sites
icon
Favicon
apple-touch-icon
iOS home screen icon
manifest
For 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