Next.js Lesson 22 – SEO with Next.js | Dataplexa
LESSON 22

SEO with Next.js

Master search engine optimization by implementing metadata, structured data, and SEO best practices to boost NewsWave's search rankings and visibility.

Search engines crawl billions of web pages every day. They need to understand what your NewsWave articles are about, who wrote them, and why users should click on them. Unlike traditional React apps that start with empty HTML files, Next.js gives you complete control over what search engines see when they visit your pages. Think of SEO like writing a newspaper headline. A bad headline might say "Thing Happened." A great headline tells you exactly what, when, and why it matters. Your webpage metadata works the same way — it tells Google, Bing, and other search engines exactly what your content offers. Next.js provides several built-in tools for SEO optimization. The Metadata API lets you control page titles, descriptions, and social media previews. The generateMetadata function creates dynamic metadata based on your content. And the built-in Head component gives you fine-grained control over everything search engines see.

The Metadata API

Next.js 13+ includes a powerful Metadata API that replaces the old Head component for most use cases. This API lets you define metadata as JavaScript objects rather than JSX elements. The system automatically handles duplicate tags, merges metadata from parent layouts, and ensures proper HTML structure. Every page and layout can export a metadata object. Next.js reads this object at build time (for static pages) or request time (for dynamic pages) and generates the appropriate HTML tags. Child pages inherit metadata from parent layouts but can override specific values. The Metadata API works like a cascade. Your root layout might define global metadata like site name and default description. Section layouts add category-specific information. Individual pages override with content-specific titles and descriptions. Search engines receive the final merged result.
// app/layout.js — Global metadata for NewsWave
export const metadata = {
  title: {
    template: '%s | NewsWave', // %s gets replaced with page title
    default: 'NewsWave - Breaking News & Analysis' // fallback title
  },
  description: 'Stay informed with breaking news, in-depth analysis, and expert commentary from around the world.',
  keywords: ['news', 'breaking news', 'analysis', 'world news']
}

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}
Generated HTML Head
<title>NewsWave - Breaking News & Analysis</title>
<meta name="description" content="Stay informed with breaking news..." />
<meta name="keywords" content="news,breaking news,analysis,world news" />
✓ Metadata API automatically generates proper HTML tags
What just happened?

Next.js read your metadata object and generated proper HTML tags in the document head. The title template sets up a pattern for child pages. The default title appears on your homepage. Try this: View page source to see the generated meta tags.

Dynamic pages need dynamic metadata. NewsWave articles should show the actual article title, author, and summary in search results. The generateMetadata function runs server-side to create metadata based on your page parameters and data.
// app/articles/[slug]/page.js — Dynamic article metadata
export async function generateMetadata({ params }) {
  // Fetch article data based on the slug parameter
  const article = await getArticle(params.slug)
  
  return {
    title: article.title, // Will use template: "Article Title | NewsWave"
    description: article.summary,
    authors: [{ name: article.author.name }],
    publishedTime: article.publishedAt,
    modifiedTime: article.updatedAt,
    section: article.category
  }
}

// Your article page component
export default async function ArticlePage({ params }) {
  const article = await getArticle(params.slug)
  return (
    <article>
      <h1>{article.title}</h1>
      <p>By {article.author.name}</p>
      <div>{article.content}</div>
    </article>
  )
}
Article Page HTML
<title>Climate Change Report Shows Alarming Trends | NewsWave</title>
<meta name="description" content="Scientists release new data on rising temperatures..." />
<meta name="author" content="Sarah Chen" />
✓ Each article gets unique metadata from your CMS data
What just happened?

The generateMetadata function ran server-side to fetch article data and create custom metadata. Each article now has a unique title, description, and author information for search engines. Try this: Visit different article URLs to see how metadata changes dynamically.

Open Graph and Social Media

When someone shares your NewsWave article on Twitter, Facebook, or LinkedIn, those platforms display a preview card. Open Graph metadata controls what appears in these previews. Without proper Open Graph tags, social platforms might show your site logo, a random image, or nothing at all. Open Graph works like a business card for your content. It tells social platforms the title, description, image, and type of content you're sharing. Twitter Cards work similarly but with Twitter-specific optimizations. Next.js makes it easy to generate both formats from the same metadata object. The image you choose for social sharing can make or break engagement. NewsWave articles might use the article's featured image, author headshot, or a custom graphic with the headline overlaid. The image should be at least 1200x630 pixels for optimal display across platforms.
// Enhanced metadata with Open Graph and Twitter Cards
export async function generateMetadata({ params }) {
  const article = await getArticle(params.slug)
  
  return {
    title: article.title,
    description: article.summary,
    // Open Graph metadata for Facebook, LinkedIn
    openGraph: {
      title: article.title,
      description: article.summary,
      type: 'article',
      publishedTime: article.publishedAt,
      authors: [article.author.name],
      images: [
        {
          url: article.featuredImage,
          width: 1200,
          height: 630,
          alt: article.imageAlt
        }
      ]
    },
    // Twitter Card metadata
    twitter: {
      card: 'summary_large_image',
      title: article.title,
      description: article.summary,
      images: [article.featuredImage]
    }
  }
}
Social Media Preview
What just happened?

Your metadata now includes Open Graph and Twitter Card information. When users share NewsWave articles, social platforms will display rich previews with your chosen title, description, and image. Try this: Test your links with Facebook's Sharing Debugger or Twitter's Card Validator.

Structured Data and JSON-LD

Structured data helps search engines understand your content beyond simple text. When you mark up a NewsWave article with structured data, Google can display rich snippets showing the author, publish date, and even star ratings in search results. This increases click-through rates significantly. JSON-LD (JavaScript Object Notation for Linked Data) is Google's preferred structured data format. Unlike microdata that clutters your HTML, JSON-LD lives in a script tag and doesn't affect your page layout. Search engines parse this structured data to create enhanced search result displays. For news articles, the most important structured data types are Article, NewsArticle, and Organization. Article schema tells search engines about your content, author, and publication date. Organization schema establishes NewsWave as a credible publisher. Publisher information builds trust with both search engines and users.
// app/articles/[slug]/page.js — Add JSON-LD structured data
export default async function ArticlePage({ params }) {
  const article = await getArticle(params.slug)
  
  // JSON-LD structured data for the article
  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'NewsArticle',
    headline: article.title,
    description: article.summary,
    image: article.featuredImage,
    author: {
      '@type': 'Person',
      name: article.author.name
    },
    publisher: {
      '@type': 'Organization',
      name: 'NewsWave',
      logo: {
        '@type': 'ImageObject',
        url: 'https://newswave.com/logo.png'
      }
    },
    datePublished: article.publishedAt,
    dateModified: article.updatedAt
  }

  return (
    <>
      {/* JSON-LD script tag for structured data */}
      <script 
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <article>
        <h1>{article.title}</h1>
        <p>By {article.author.name}</p>
        <div>{article.content}</div>
      </article>
    </>
  )
}
Google Rich Results Test
✓ NewsArticle schema detected
- Headline: "Climate Change Report Shows Alarming Trends"
- Author: Sarah Chen
- Publisher: NewsWave
- Published: 2024-01-15
✓ Eligible for news article rich snippets
What just happened?

You added JSON-LD structured data that tells search engines this is a news article with specific author and publisher information. Google can now show enhanced search results with publish dates, author names, and publisher logos. Try this: Test your structured data with Google's Rich Results Test tool.

Sitemaps and Robots.txt

Search engines discover your content by following links and reading sitemaps. A sitemap is like a table of contents for your entire website — it lists all your pages, when they were last updated, and how often they change. Next.js can generate sitemaps automatically from your content. NewsWave might have thousands of articles across multiple categories. A static sitemap would quickly become outdated. Dynamic sitemaps generate automatically from your content management system, ensuring search engines always know about your latest articles. You can create separate sitemaps for articles, categories, and static pages. The robots.txt file tells search engines which parts of your site to crawl and which to ignore. You might want to block crawlers from your admin pages, draft articles, or development environments. Next.js serves robots.txt from your public directory automatically.
// app/sitemap.js — Dynamic sitemap generation
export default async function sitemap() {
  // Fetch all published articles from your CMS
  const articles = await getAllArticles()
  
  // Create sitemap entries for articles
  const articleEntries = articles.map(article => ({
    url: `https://newswave.com/articles/${article.slug}`,
    lastModified: article.updatedAt,
    changeFrequency: 'daily', // News articles change frequently
    priority: 0.8 // High priority for article content
  }))
  
  // Static pages with different priorities
  const staticPages = [
    {
      url: 'https://newswave.com',
      lastModified: new Date(),
      changeFrequency: 'hourly',
      priority: 1.0 // Homepage is highest priority
    },
    {
      url: 'https://newswave.com/about',
      lastModified: new Date('2024-01-01'),
      changeFrequency: 'monthly',
      priority: 0.5 // Lower priority for static content
    }
  ]
  
  return [...staticPages, ...articleEntries]
}
# public/robots.txt — Control search engine crawling
User-agent: *
Allow: /

# Block crawlers from admin areas
Disallow: /admin/
Disallow: /api/
Disallow: /drafts/

# Point to your sitemap
Sitemap: https://newswave.com/sitemap.xml
Generated Sitemap Preview
<url>
<loc>https://newswave.com/articles/climate-report</loc>
<lastmod>2024-01-15T10:30:00Z</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
✓ Sitemap automatically updates when you publish articles
What just happened?

Next.js generated a dynamic sitemap that updates automatically when you publish new articles. Your robots.txt file guides search engines to crawl your content while avoiding private areas. Try this: Visit /sitemap.xml to see your generated sitemap and submit it to Google Search Console.

Performance and Core Web Vitals

Search engines consider page loading speed as a ranking factor. Google's Core Web Vitals measure three key performance metrics: Largest Contentful Paint (how quickly main content loads), First Input Delay (how quickly your page responds to user interaction), and Cumulative Layout Shift (how much your page jumps around while loading). Next.js helps with Core Web Vitals through automatic optimizations. The Image component prevents layout shift by reserving space for images. Font optimization reduces text rendering delays. Automatic code splitting ensures users only download code they need. Server-side rendering displays content faster than client-side React apps. However, you still need to monitor and optimize. Large images can hurt Largest Contentful Paint. Heavy JavaScript can increase First Input Delay. Missing image dimensions cause Cumulative Layout Shift. NewsWave articles with many images and interactive elements need careful optimization.
// Optimized article page for Core Web Vitals
import Image from 'next/image'

export default function ArticlePage({ article }) {
  return (
    <article>
      {/* Next.js Image component prevents layout shift */}
      <Image
        src={article.featuredImage}
        alt={article.imageAlt}
        width={800}
        height={400}
        priority // Load above-the-fold images immediately
        placeholder="blur"
        blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
      />
      
      <h1>{article.title}</h1>
      
      {/* Lazy load images below the fold */}
      {article.bodyImages.map(image => (
        <Image
          key={image.id}
          src={image.url}
          alt={image.alt}
          width={600}
          height={300}
          loading="lazy" // Default behavior, but explicit is better
        />
      ))}
    </article>
  )
}
Core Web Vitals Dashboard
What just happened?

Your optimized article page loads quickly and prevents layout shifts through proper image sizing and lazy loading. Good Core Web Vitals scores help your search rankings and provide better user experience. Try this: Use Google PageSpeed Insights to test your actual Core Web Vitals scores.

SEO Monitoring and Analytics

SEO optimization doesn't end when you publish your metadata and structured data. You need to monitor how search engines index your content, which keywords drive traffic, and where you can improve. Google Search Console shows you exactly how Google sees your NewsWave articles. Search Console reveals which queries bring users to your articles, your average position in search results, and any indexing errors Google encounters. You might discover that your climate change article ranks well for "global warming trends" but not "climate data analysis" — insights that help you optimize future content. Next.js makes it easy to add analytics tracking without hurting performance. The built-in Script component can load Google Analytics, Google Tag Manager, or other tracking tools with optimal timing. You want analytics data without slowing down your Core Web Vitals scores.
// app/layout.js — Add Google Analytics with optimal loading
import Script from 'next/script'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        
        {/* Google Analytics with optimal loading strategy */}
        <Script
          src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
          strategy="afterInteractive" // Load after page becomes interactive
        />
        <Script id="google-analytics" strategy="afterInteractive">
          {`
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', 'GA_MEASUREMENT_ID');
          `}
        </Script>
      </body>
    </html>
  )
}
// Track article engagement for SEO insights
'use client'
import { useEffect } from 'react'

export default function ArticleAnalytics({ article }) {
  useEffect(() => {
    // Track article view with category and author data
    if (typeof gtag !== 'undefined') {
      gtag('event', 'article_view', {
        article_title: article.title,
        article_category: article.category,
        article_author: article.author.name,
        article_published: article.publishedAt
      })
    }
    
    // Track reading depth for engagement metrics
    const handleScroll = () => {
      const scrolled = Math.round((window.scrollY / document.body.scrollHeight) * 100)
      if (scrolled > 50 && scrolled < 55) {
        gtag('event', 'article_half_read', {
          article_title: article.title
        })
      }
    }
    
    window.addEventListener('scroll', handleScroll)
    return () => window.removeEventListener('scroll', handleScroll)
  }, [article])

  return null // This component only tracks, doesn't render
}
Search Console Insights
Top Queries for NewsWave Articles:
"climate change report 2024" - Position 3.2 - 1,450 clicks
"global warming trends" - Position 5.8 - 890 clicks
"environmental news today" - Position 12.1 - 340 clicks
✓ Core Web Vitals: All URLs pass assessment
What just happened?

You added performance-optimized analytics tracking and detailed engagement metrics. The Script component loads analytics without blocking page rendering. Search Console data shows which keywords drive traffic to your articles. Try this: Set up Google Search Console and submit your sitemap to start collecting SEO data.

The NewsWave team now has a complete SEO strategy. Your articles generate proper metadata automatically. Social media shares display rich previews. Search engines understand your content structure through JSON-LD markup. Performance optimizations keep Core Web Vitals scores healthy. And analytics track which SEO efforts drive real results. But SEO success takes time. Search engines need weeks or months to fully index and rank new content. Keep publishing high-quality articles with proper optimization. Monitor your Search Console data monthly. Test new structured data formats. And remember — great content optimized for search engines beats mediocre content with perfect technical SEO every time.

Quiz

1. NewsWave articles need different titles and descriptions in search results. How should you create dynamic metadata for article pages in Next.js?


2. Google should display NewsWave articles with author names and publish dates in search results. What's the best way to provide this structured data?


3. NewsWave publishes new articles daily and needs search engines to discover them quickly. How should you handle sitemaps in Next.js?


Up Next: Internationalization

Build multilingual websites that serve users worldwide with Next.js internationalization features, automatic locale detection, and translated routing.