CodingNeed.

3 · Reliability and delivery · 45 MIN

Project · A public course page with accurate metadata

Discoverable pages need meaningful HTML and resource-specific metadata.

A public course page should explain its prerequisites, syllabus and learning outcomes before asking a visitor to enroll. generateMetadata can derive a unique title and description from the same resource lookup used by the page. A canonical identifies the preferred public URL; it does not force indexing. Keep account pages private where appropriate and omit them from the public sitemap. This project uses a fixed trusted origin and validated known slugs rather than constructing canonical URLs from arbitrary request headers.

Inspect the document title and canonical for each published course.

Read the example

// app/courses/[slug]/page.tsx
import type {Metadata} from 'next';
import {notFound} from 'next/navigation';
const catalog={react:{title:'React foundations',summary:'Learn components, props, state and effect cleanup.'}};
type Props={params:Promise<{slug:string}>};
function find(slug:string){if(slug!=='react')notFound();return catalog.react}
export async function generateMetadata({params}:Props):Promise<Metadata>{
  const {slug}=await params;const course=find(slug);
  return {title:course.title,description:course.summary,alternates:{canonical:'https://example.com/courses/'+encodeURIComponent(slug)}};
}
export default async function Page({params}:Props){const course=find((await params).slug);return <main><h1>{course.title}</h1><p>{course.summary}</p><h2>Prerequisites</h2><p>JavaScript functions and arrays.</p><h2>Syllabus</h2><ol><li>Components</li><li>State</li><li>Effect cleanup</li></ol></main>}
Check the expected output
The React route contains a title, description, canonical and visible prerequisites and syllabus. Unknown slugs still use notFound.

Your challenge

Replace example.com with your project’s configured origin; add a sitemap containing only the published course URLs and verify server-rendered HTML.

Solution cost: O(1) lookup for this one-resource example. time · O(s) rendered syllabus content. space

Common trap

Metadata alone cannot make thin, inaccessible or blocked content rank.

Study the project implementation
// app/courses/[slug]/page.tsx
import type {Metadata} from 'next';
import {notFound} from 'next/navigation';
const catalog={react:{title:'React foundations',summary:'Learn components, props, state and effect cleanup.'}};
type Props={params:Promise<{slug:string}>};
function find(slug:string){if(slug!=='react')notFound();return catalog.react}
export async function generateMetadata({params}:Props):Promise<Metadata>{
  const {slug}=await params;const course=find(slug);
  return {title:course.title,description:course.summary,alternates:{canonical:'https://example.com/courses/'+encodeURIComponent(slug)}};
}
export default async function Page({params}:Props){const course=find((await params).slug);return <main><h1>{course.title}</h1><p>{course.summary}</p><h2>Prerequisites</h2><p>JavaScript functions and arrays.</p><h2>Syllabus</h2><ol><li>Components</li><li>State</li><li>Effect cleanup</li></ol></main>}

Further reading: Official documentation

Essential cookies keep your account signed in. Optional analytics is not configured on this site. Your choice does not affect access to lessons.

Read the Privacy Policy. You can change this choice in the footer.