--- status: "published" label: "SEO" title: "SEO Configuration for the Next.js Supabase Starter Kit" description: "Configure sitemaps, metadata, structured data, and search engine optimization for your Makerkit SaaS application." order: 10 --- SEO in Makerkit starts with Next.js Metadata API for page-level optimization, an auto-generated sitemap at `/sitemap.xml`, and proper robots.txt configuration. The kit handles technical SEO out of the box, so you can focus on content quality and backlink strategy. {% sequence title="SEO Configuration" description="Set up search engine optimization for your SaaS" %} [Configure page metadata](#page-metadata) [Customize the sitemap](#sitemap-configuration) [Add structured data](#structured-data) [Submit to Google Search Console](#google-search-console) {% /sequence %} ## Page Metadata ### Next.js Metadata API Use the Next.js Metadata API to set page-level SEO: ```tsx {% title="apps/web/app/[locale]/(marketing)/pricing/page.tsx" %} import type { Metadata } from 'next'; export const metadata: Metadata = { title: 'Pricing | Your SaaS Name', description: 'Simple, transparent pricing. Start free, upgrade when you need more.', openGraph: { title: 'Pricing | Your SaaS Name', description: 'Simple, transparent pricing for teams of all sizes.', images: ['/images/og/pricing.png'], type: 'website', }, twitter: { card: 'summary_large_image', title: 'Pricing | Your SaaS Name', description: 'Simple, transparent pricing for teams of all sizes.', images: ['/images/og/pricing.png'], }, }; export default function PricingPage() { // ... } ``` ### Dynamic Metadata For pages with dynamic content, use `generateMetadata`: ```tsx {% title="apps/web/app/[locale]/(marketing)/blog/[slug]/page.tsx" %} import type { Metadata } from 'next'; import { createCmsClient } from '@kit/cms'; interface Props { params: Promise<{ slug: string }>; } export async function generateMetadata({ params }: Props): Promise { const { slug } = await params; const cms = await createCmsClient(); const post = await cms.getContentBySlug({ slug, collection: 'posts' }); return { title: `${post.title} | Your SaaS Blog`, description: post.description, openGraph: { title: post.title, description: post.description, images: [post.image], type: 'article', publishedTime: post.publishedAt, }, }; } ``` ### Global Metadata Set default metadata in your root layout at `apps/web/app/layout.tsx`: ```tsx {% title="apps/web/app/layout.tsx" %} import type { Metadata } from 'next'; import appConfig from '~/config/app.config'; export const metadata: Metadata = { title: { default: appConfig.name, template: `%s | ${appConfig.name}`, }, description: appConfig.description, metadataBase: new URL(appConfig.url), openGraph: { type: 'website', locale: 'en_US', siteName: appConfig.name, }, robots: { index: true, follow: true, }, }; ``` ## Sitemap Configuration Makerkit auto-generates a sitemap at `/sitemap.xml`. The configuration lives in `apps/web/app/sitemap.xml/route.ts`. ### Adding Static Pages Add new pages to the `getPaths` function: ```tsx {% title="apps/web/app/sitemap.xml/route.ts" %} import appConfig from '~/config/app.config'; function getPaths() { const paths = [ '/', '/pricing', '/faq', '/blog', '/docs', '/contact', '/about', // Add new pages '/features', '/privacy-policy', '/terms-of-service', '/cookie-policy', ]; return paths.map((path) => ({ loc: new URL(path, appConfig.url).href, lastmod: new Date().toISOString(), })); } ``` ### Dynamic Content Blog posts and documentation pages are automatically added to the sitemap. The CMS integration handles this: ```tsx // Blog posts are added automatically const posts = await cms.getContentItems({ collection: 'posts' }); posts.forEach((post) => { sitemap.push({ loc: new URL(`/blog/${post.slug}`, appConfig.url).href, lastmod: post.updatedAt || post.publishedAt, }); }); ``` ### Excluding Pages Exclude pages from the sitemap by not including them in `getPaths()`. For pages that should not be indexed at all, use the `robots` metadata: ```tsx export const metadata: Metadata = { robots: { index: false, follow: false, }, }; ``` ## Structured Data Add JSON-LD structured data for rich search results. See the [Next.js JSON-LD guide](https://nextjs.org/docs/app/guides/json-ld) for the recommended approach. ### Organization Schema Add to your home page or layout: ```tsx {% title="apps/web/app/[locale]/(marketing)/page.tsx" %} // JSON-LD structured data using a script tag export default function HomePage() { return ( <>