SEO Configuration for the Next.js Supabase Starter Kit

Configure sitemaps, metadata, structured data, and search engine optimization for your Makerkit SaaS application.

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.

SEO Configuration

Set up search engine optimization for your SaaS

Page Metadata

Next.js Metadata API

Use the Next.js Metadata API to set page-level SEO:

apps/web/app/(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:

apps/web/app/(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<Metadata> {
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:

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:

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(),
changefreq: 'weekly',
priority: path === '/' ? 1.0 : 0.8,
}));
}

Dynamic Content

Blog posts and documentation pages are automatically added to the sitemap. The CMS integration handles this:

// 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,
changefreq: 'monthly',
priority: 0.6,
});
});

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:

export const metadata: Metadata = {
robots: {
index: false,
follow: false,
},
};

Structured Data

Add JSON-LD structured data for rich search results.

Organization Schema

Add to your home page or layout:

apps/web/app/(marketing)/page.tsx

import { JsonLd } from '@kit/ui/json-ld';
export default function HomePage() {
return (
<>
<JsonLd
data={{
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Your SaaS Name',
url: 'https://yoursaas.com',
logo: 'https://yoursaas.com/logo.png',
sameAs: [
'https://twitter.com/yoursaas',
'https://github.com/yoursaas',
],
}}
/>
{/* Page content */}
</>
);
}

Product Schema

Add to your pricing page:

apps/web/app/(marketing)/pricing/page.tsx

<JsonLd
data={{
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'Your SaaS Name',
applicationCategory: 'BusinessApplication',
offers: {
'@type': 'AggregateOffer',
lowPrice: '0',
highPrice: '99',
priceCurrency: 'USD',
offerCount: 3,
},
}}
/>

FAQ Schema

Use the Markdoc FAQ node for automatic FAQ schema:

{% faq
title="Frequently Asked Questions"
items=[
{"question": "How do I get started?", "answer": "Sign up for a free account..."},
{"question": "Can I cancel anytime?", "answer": "Yes, you can cancel..."}
]
/%}

Article Schema

Add to blog posts:

<JsonLd
data={{
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
description: post.description,
image: post.image,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
'@type': 'Person',
name: post.author,
},
}}
/>

Robots.txt

The robots.txt file is at apps/web/public/robots.txt:

apps/web/public/robots.txt

User-agent: *
Allow: /
Disallow: /home/
Disallow: /admin/
Disallow: /api/
Sitemap: https://yoursaas.com/sitemap.xml

Update the sitemap URL to your production domain.

Google Search Console

Verification

  1. Go to Google Search Console
  2. Add your property (URL prefix method)
  3. Choose verification method:
    • HTML tag: Add to your root layout's metadata
    • HTML file: Upload to public/
// HTML tag verification
export const metadata: Metadata = {
verification: {
google: 'your-verification-code',
},
};

Submit Sitemap

After verification:

  1. Navigate to Sitemaps in Search Console
  2. Enter sitemap.xml in the input field
  3. Click Submit

Google will crawl and index your sitemap within a few days.

Monitor Indexing

Check Search Console regularly for:

  • Coverage: Pages indexed vs. excluded
  • Enhancements: Structured data validation
  • Core Web Vitals: Performance metrics
  • Mobile Usability: Mobile-friendly issues

SEO Best Practices

Content Quality

Content quality matters more than technical SEO. Focus on:

  • Helpful content: Solve problems your customers search for
  • Unique value: Offer insights competitors don't have
  • Regular updates: Keep content fresh and accurate
  • Comprehensive coverage: Answer related questions

Keyword Strategy

ElementRecommendation
TitlePrimary keyword near the beginning
DescriptionInclude keyword naturally, focus on click-through
H1One per page, include primary keyword
URLShort, descriptive, include keyword
ContentUse variations naturally, don't stuff

Image Optimization

import Image from 'next/image';
<Image
src="/images/feature-screenshot.webp"
alt="Dashboard showing project analytics with team activity"
width={1200}
height={630}
priority={isAboveFold}
/>
  • Use WebP format for better compression
  • Include descriptive alt text with keywords
  • Use descriptive filenames (project-dashboard.webp not img1.webp)
  • Size images appropriately for their display size

Internal Linking

Link between related content:

// In your blog post about authentication
<p>
Learn more about{' '}
<Link href="/docs/authentication/setup">
setting up authentication
</Link>{' '}
in our documentation.
</p>

Page Speed

Makerkit is optimized for performance out of the box:

  • Next.js automatic code splitting
  • Image optimization with next/image
  • Font optimization with next/font
  • Static generation for marketing pages

Check your scores with PageSpeed Insights.

Backlinks remain the strongest ranking factor. Strategies that work:

StrategyEffortImpact
Create linkable content (guides, tools, research)HighHigh
Guest posting on relevant blogsMediumMedium
Product directories (Product Hunt, etc.)LowMedium
Open source contributionsMediumMedium
Podcast appearancesMediumMedium

Focus on quality over quantity. One link from a high-authority site beats dozens of low-quality links.

Timeline Expectations

SEO takes time. Typical timelines:

MilestoneTimeline
Initial indexing1-2 weeks
Rankings for low-competition terms1-3 months
Rankings for medium-competition terms3-6 months
Rankings for high-competition terms6-12+ months

Keep creating content and building backlinks. Results compound over time.