Going to production · Lesson 13 of 16
Metadata and SEO
metadata and generateMetadata, share images, sitemap and robots.
The title, description and share image are what show up on Google, WhatsApp and LinkedIn. In Next.js you export metadata (static) or generateMetadata (for pages with dynamic data) from any page.tsx or layout.tsx, and Next.js turns them into <head> tags.
// app/layout.tsx: defaults for the whole site
import type { Metadata } from "next"
export const metadata: Metadata = {
metadataBase: new URL("https://www.seacode.tech"),
title: { default: "SeaCode", template: "%s · SeaCode" }, // pages fill in %s
description: "Learn to code for real, in Arabic and English.",
openGraph: { type: "website", siteName: "SeaCode" },
}
// app/courses/[slug]/page.tsx: per-course metadata from the database
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
const { slug } = await params
const course = await getCourse(slug)
if (!course) return { title: "Course not found" }
return {
title: course.title, // "React · SeaCode"
description: course.summary,
openGraph: { images: [course.thumbnailUrl] },
alternates: { canonical: "/courses/" + slug },
}
}// app/sitemap.ts -> /sitemap.xml
import type { MetadataRoute } from "next"
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const courses = await getAllCourses()
return [
{ url: "https://www.seacode.tech", changeFrequency: "weekly", priority: 1 },
...courses.map((c) => ({ url: "https://www.seacode.tech/courses/" + c.slug, lastModified: c.updatedAt })),
]
}
// app/robots.ts -> /robots.txt
export default function robots(): MetadataRoute.Robots {
return { rules: { userAgent: "*", allow: "/", disallow: ["/admin", "/api"] }, sitemap: "https://www.seacode.tech/sitemap.xml" }
}generateMetadata loads the course
<title>React · SeaCode</title> + og:image
Google and social apps read the head
Quick question
The root layout has title.template: "%s · SeaCode" and the course page has title: "SQL". What's the tab title?
Exercise
Write a simplified generateMetadata(course) returning { title, description }: the title is the course name, and the description is the first 50 characters of the summary followed by … if it was longer. For a null course return { title: "Course not found" }. Print the results with JSON.stringify.
{"title":"SQL","description":"Query real data."}
{"title":"React","description":"Build interactive interfaces from small components…"}
{"title":"Course not found"}function generateMetadata(course) {
return {}
}
console.log(JSON.stringify(generateMetadata({ title: "SQL", summary: "Query real data." })))
console.log(JSON.stringify(generateMetadata({ title: "React", summary: "Build interactive interfaces from small components, with state and effects." })))
console.log(JSON.stringify(generateMetadata(null)))Learn more from
Played 0 of 2 games
Sign in to save your progress and earn XP.