
Key takeaways
- Export a typed
metadataobject orgenerateMetadatafrom an App Router page or layout. - Place
app/sitemap.tsin the app directory and list the canonical URLs you want crawled. - Check the actual server response for a title, canonical and meaningful content; a browser view alone can hide rendering problems.
A Next.js App Router page needs the same basic SEO signals as any other page: a distinct purpose, a readable server response, a canonical URL and internal links. Next.js provides file-based metadata and sitemap conventions, but the code only helps when it matches the public content.
The compact example below uses example.com and an illustrative SEO service page. Adapt the paths and copy to your site. It follows the current Next.js metadata and sitemap documentation; no client results are implied.
Set a base URL in the root layout
Relative canonical and Open Graph paths need a known base. In app/layout.tsx, set metadataBase to your production origin. This small example includes the required root layout structure:
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
}
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return <html lang="en"><body>{children}</body></html>
}Replace https://example.com before deployment. Keep the production domain consistent across metadata, sitemap and redirects. A staging URL accidentally used as the base can leak into canonical and sharing tags.
Give the page its own metadata and visible answer
For a stable page, export a typed metadata object from app/services/seo-audit/page.tsx. The page component itself should return the promised main content:
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'SEO audit in Nepal | Example Studio',
description: 'See the scope, process and deliverables for an SEO audit.',
alternates: { canonical: '/services/seo-audit/' },
openGraph: {
title: 'SEO audit in Nepal | Example Studio',
description: 'Scope, process and deliverables for an SEO audit.',
url: '/services/seo-audit/',
images: ['/og/seo-audit.jpg'],
},
}
export default function Page() {
return <main><h1>SEO audit in Nepal</h1>
<p>We check crawling, content, internal links and measurement.</p>
</main>
}The page is a Server Component by default in the App Router. That makes the heading and short introduction part of the server-rendered page in this simple example. If your real page fetches content, handles authentication or streams components, inspect its actual deployed response. For dynamic routes, Next.js documents generateMetadata; build the title and canonical from the same record used by the page.
Publish a sitemap of canonical URLs
Create app/sitemap.ts and return the URLs you want search engines to consider. This example uses the typed metadata route:
import type { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
return [
{ url: 'https://example.com/', lastModified: new Date('2026-09-25') },
{ url: 'https://example.com/services/seo-audit/',
lastModified: new Date('2026-09-25') },
]
}Generate entries from real published pages in a production site; do not stamp every URL with today's date on each request if the page has not changed. Exclude internal search results, duplicate filters, login pages and removed routes. Test the deployed /sitemap.xml and link important pages through ordinary navigation as well.
Verify the deployed HTML and indexing path
- Load the URL directly with JavaScript disabled or inspect its raw HTML response. Check for a meaningful
<title>, meta description, canonical and H1. - Check that the important paragraph and links are available without waiting for a client-only API call.
- Open the deployed sitemap and confirm it lists the preferred URLs.
- In Search Console, inspect a representative URL and compare Google's selected canonical with your declared canonical.
This article is a code example, not a claim that this separate static website runs Next.js. For broader rendering, robots and hydration issues, read the JavaScript SEO guide. A framework configuration cannot substitute for useful content or working internal links.
Common App Router mistakes to check
A shared layout title can leave every route with the same search snippet. Confirm that important service and article pages export their own metadata. If you use generateMetadata for dynamic pages, return a meaningful title and canonical for each published slug, and handle missing records with a real not-found response. Keep preview and staging domains out of the production sitemap.
Client Components are appropriate for interactive filters or forms, but the main answer should still be available in the route's rendered output. Inspect a product or article URL directly, not only after navigating from the homepage. Finally, check that the Open Graph image actually exists and has an appropriate size; a correct metadata object pointing to a missing image still produces a broken share preview. Recheck representative pages after framework upgrades.
Sources and further reading
Need a rendered-content and metadata review for a Next.js site?
Get in touch