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 automaticallyconst 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.xmlUpdate the sitemap URL to your production domain.
Google Search Console
Verification
- Go to Google Search Console
- Add your property (URL prefix method)
- Choose verification method:
- HTML tag: Add to your root layout's metadata
- HTML file: Upload to
public/
// HTML tag verificationexport const metadata: Metadata = { verification: { google: 'your-verification-code', },};Submit Sitemap
After verification:
- Navigate to Sitemaps in Search Console
- Enter
sitemap.xmlin the input field - 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
| Element | Recommendation |
|---|---|
| Title | Primary keyword near the beginning |
| Description | Include keyword naturally, focus on click-through |
| H1 | One per page, include primary keyword |
| URL | Short, descriptive, include keyword |
| Content | Use 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.webpnotimg1.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
Backlinks remain the strongest ranking factor. Strategies that work:
| Strategy | Effort | Impact |
|---|---|---|
| Create linkable content (guides, tools, research) | High | High |
| Guest posting on relevant blogs | Medium | Medium |
| Product directories (Product Hunt, etc.) | Low | Medium |
| Open source contributions | Medium | Medium |
| Podcast appearances | Medium | Medium |
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:
| Milestone | Timeline |
|---|---|
| Initial indexing | 1-2 weeks |
| Rankings for low-competition terms | 1-3 months |
| Rankings for medium-competition terms | 3-6 months |
| Rankings for high-competition terms | 6-12+ months |
Keep creating content and building backlinks. Results compound over time.
Related Resources
- Marketing Pages for building optimized landing pages
- CMS Setup for content marketing
- App Configuration for base URL and metadata settings