Learn how to optimize your Next.js application for search engines using metadata, structured data, and best practices.
Next.js 13+ provides a powerful Metadata API for managing SEO-related tags. Here's how to implement basic metadata:
1import { Metadata } from 'next'23export const metadata: Metadata = {4 title: 'Your Site Name',5 description: 'Your site description goes here',6 keywords: ['nextjs', 'react', 'web development'],7 authors: [{ name: 'Your Name' }],8 openGraph: {9 title: 'Your Site Name',10 description: 'Your site description goes here',11 url: 'https://yoursite.com',12 siteName: 'Your Site Name',13 images: [14 {15 url: 'https://yoursite.com/og.png',16 width: 1200,17 height: 630,18 },19 ],20 locale: 'en_US',21 type: 'website',22 },23 twitter: {24 card: 'summary_large_image',25 title: 'Your Site Name',26 description: 'Your site description goes here',27 creator: '@yourusername',28 images: ['https://yoursite.com/og.png'],29 },30 robots: {31 index: true,32 follow: true,33 googleBot: {34 index: true,35 follow: true,36 'max-video-preview': -1,37 'max-image-preview': 'large',38 'max-snippet': -1,39 },40 },41 icons: {42 icon: '/favicon.ico',43 shortcut: '/favicon-16x16.png',44 apple: '/apple-touch-icon.png',45 },46}
Generate dynamic metadata based on the current route or data:
1import { Metadata } from 'next'2import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'3import { cookies } from 'next/headers'45interface Props {6 params: { slug: string }7}89export async function generateMetadata({ params }: Props): Promise<Metadata> {10 const supabase = createServerComponentClient({ cookies })1112 const { data: post } = await supabase13 .from('posts')14 .select('title, description, image_url')15 .eq('slug', params.slug)16 .single()1718 if (!post) {19 return {20 title: 'Post Not Found',21 description: 'The post you're looking for does not exist',22 }23 }2425 return {26 title: post.title,27 description: post.description,28 openGraph: {29 title: post.title,30 description: post.description,31 images: [32 {33 url: post.image_url,34 width: 1200,35 height: 630,36 alt: post.title,37 },38 ],39 },40 }41}
Add structured data to help search engines better understand your content:
1import { JsonLd } from 'react-schemaorg'23export default function BlogPost({4 post,5 author,6}: {7 post: Post8 author: Author9}) {10 return (11 <>12 <JsonLd<BlogPosting>13 item={{14 '@context': 'https://schema.org',15 '@type': 'BlogPosting',16 headline: post.title,17 description: post.description,18 image: post.image_url,19 datePublished: post.published_at,20 dateModified: post.updated_at,21 author: {22 '@type': 'Person',23 name: author.name,24 },25 publisher: {26 '@type': 'Organization',27 name: 'Your Company Name',28 logo: {29 '@type': 'ImageObject',30 url: 'https://yoursite.com/logo.png',31 },32 },33 }}34 />35 {/* Your blog post content */}36 </>37 )38}
article, section, nav, etc.