SEO in SaaS Boilerplates: What Most Get Wrong in 2026
TL;DR
Most boilerplates focus on the app — auth, billing, dashboard. SEO for the marketing site is often incomplete or wrong. Key gaps: missing structured data, incorrect canonical URLs, no sitemap generation, poor meta descriptions, and app routes leaking into search indexes. These are fixable in a day but have a large long-term impact.
Why SEO Matters More for SaaS Than You Think
For most SaaS companies, organic search is the lowest-CAC (customer acquisition cost) channel. Paid acquisition for SaaS can run $50-300+ per trial signup depending on the category. Organic search, once established, delivers leads at near-zero marginal cost. The difference compounds over years: a product with good SEO in year one still gets traffic from that investment in year three, while paid spend stops working the moment you stop paying.
The SEO opportunity for SaaS boilerplate-based products specifically is large because most boilerplate-based projects have identical technical foundations. The boilerplate provides the app; the differentiation is content and positioning. A founder who invests one week in solid SEO infrastructure at launch — canonical URLs, structured data, dynamic sitemaps, OG image generation — creates an advantage that compounds as their content library grows.
The content flywheel for SaaS SEO: you write comparison pages ("YourTool vs Competitor"), how-to guides ("How to do X with YourTool"), and use case pages ("YourTool for [job title]"). These pages capture intent-rich search traffic from people actively researching solutions to the problem you solve. Paid ads can't replicate this — they stop the moment the budget runs out. The organic visitors reading your comparison page six months from now started their session because of something you published today.
What SaaS Boilerplates Get Right
A well-configured Next.js boilerplate ships with:
// app/layout.tsx — global metadata
export const metadata: Metadata = {
title: {
default: 'YourSaaS — Short Description',
template: '%s | YourSaaS',
},
description: 'Compelling 150-160 character description with primary keyword.',
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://yoursaas.com',
siteName: 'YourSaaS',
},
twitter: {
card: 'summary_large_image',
creator: '@yoursaas',
},
};
This is the minimum. Most boilerplates stop here.
What Boilerplates Get Wrong
1. No Canonical URLs
Without canonicals, duplicate content (HTTP vs HTTPS, www vs non-www, trailing slashes) hurts rankings:
// app/layout.tsx — add canonical
export const metadata: Metadata = {
alternates: {
canonical: 'https://yoursaas.com',
},
};
// app/blog/[slug]/page.tsx — per-page canonical
export async function generateMetadata({ params }): Promise<Metadata> {
return {
alternates: {
canonical: `https://yoursaas.com/blog/${params.slug}`,
},
};
}
2. Missing Structured Data
Rich results (star ratings, FAQ accordions, breadcrumbs) require JSON-LD:
// components/json-ld.tsx
export function ArticleJsonLd({ post }: { post: Post }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
description: post.description,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
'@type': 'Organization',
name: 'YourSaaS',
url: 'https://yoursaas.com',
},
publisher: {
'@type': 'Organization',
name: 'YourSaaS',
logo: { '@type': 'ImageObject', url: 'https://yoursaas.com/logo.png' },
},
image: post.ogImage ?? 'https://yoursaas.com/og-default.png',
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
);
}
// For SaaS homepage — SoftwareApplication schema
export function SoftwareJsonLd() {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'YourSaaS',
applicationCategory: 'BusinessApplication',
operatingSystem: 'Web',
offers: {
'@type': 'Offer',
price: '29',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '120',
},
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
);
}
3. App Routes in Search Index
Your /dashboard, /settings, and /api/* routes should not be indexed:
# public/robots.txt
User-agent: *
Allow: /
Disallow: /dashboard/
Disallow: /settings/
Disallow: /api/
Disallow: /auth/
Sitemap: https://yoursaas.com/sitemap.xml
// Or via Next.js metadata
export const metadata: Metadata = {
robots: {
index: false,
follow: false,
},
};
// Apply to app layout
// app/(app)/layout.tsx — dashboard routes
export const metadata: Metadata = {
robots: 'noindex, nofollow',
};
4. No Sitemap Generation
A sitemap tells search engines which pages to crawl. Dynamic pages (blog, comparison pages) need dynamic sitemaps:
// app/sitemap.ts
import { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await prisma.post.findMany({
where: { published: true },
select: { slug: true, updatedAt: true },
});
const blogUrls = posts.map((post) => ({
url: `https://yoursaas.com/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly' as const,
priority: 0.7,
}));
return [
{
url: 'https://yoursaas.com',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 1.0,
},
{
url: 'https://yoursaas.com/pricing',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.9,
},
...blogUrls,
];
}
5. Poor OG Image Generation
Social previews drive link click-through. Boilerplates often have a static OG image that's the same for every page:
// app/blog/[slug]/opengraph-image.tsx — Dynamic OG images
import { ImageResponse } from 'next/og';
export const size = { width: 1200, height: 630 };
export const contentType = 'image/png';
export default async function Image({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return new ImageResponse(
(
<div
style={{
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)',
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
padding: '80px',
justifyContent: 'center',
}}
>
<div style={{ fontSize: 48, fontWeight: 700, color: 'white', marginBottom: 24 }}>
{post.title}
</div>
<div style={{ fontSize: 24, color: '#94a3b8' }}>
{post.description}
</div>
<div style={{ position: 'absolute', bottom: 40, right: 80, color: '#64748b', fontSize: 20 }}>
YourSaaS.com
</div>
</div>
),
size
);
}
Core Web Vitals: The Technical SEO Layer
Google uses Core Web Vitals as a ranking signal. The three metrics that matter and how boilerplate-based apps commonly fail them:
Largest Contentful Paint (LCP < 2.5s): LCP measures how long the largest visible element takes to load. For SaaS landing pages, this is usually the hero image or hero section. Common failures: large unoptimized hero images (3MB PNG files), fonts that block rendering, or layout that causes the LCP element to shift during load. Fix: use Next.js <Image> with priority for above-the-fold images, preload the hero font, and serve images from a CDN.
Cumulative Layout Shift (CLS < 0.1): CLS measures unexpected layout movement — elements that jump around as the page loads. Common failures: images without explicit width/height attributes (browser doesn't reserve space), fonts swapping on load (FOIT/FOUT), and banners or alerts that load after the main content and push everything down. Fix: always set image dimensions, use font-display: optional to prevent FOUT, and avoid injecting content above existing content.
Interaction to Next Paint (INP < 200ms): INP replaced FID in 2024 and measures responsiveness to user interactions across the full page lifecycle. Common failures: large JavaScript bundles that block the main thread, synchronous long-running operations in event handlers, and heavy third-party scripts (chat widgets, analytics). Fix: lazy-load third-party scripts with next/script using strategy="lazyOnload", code-split with dynamic imports, and avoid blocking the main thread in click handlers.
Blog-Driven SEO Strategy for SaaS
The SEO infrastructure above gets your existing pages indexed correctly. The content strategy determines what traffic you attract. For SaaS products specifically, three content types have the highest conversion rate from organic traffic:
Comparison pages ("YourTool vs Competitor"): Users searching "[your category] vs [competitor]" are deep in the evaluation stage — they've identified their need and are comparing solutions. These pages convert at 3-5x the rate of generic informational content because the intent is highly commercial. Build one comparison page for each of your 3-5 main competitors.
Alternative pages ("[Competitor] alternatives"): Similar intent to comparison pages but captures users who have already decided to leave the competitor. "Best X alternatives" pages target this segment. They typically have higher search volume than direct comparison queries.
Use case / job title pages ("YourTool for [role]" or "How to do X with YourTool"): These capture users searching for solutions to specific problems you solve. They have lower search volume per page but cover the long tail of use cases, and they signal product breadth to search engines.
The internal linking structure between these page types matters significantly for SEO. Comparison pages should link to your pricing page, sign-up page, and relevant how-to guides. How-to guides should link to comparison pages and the specific product feature they demonstrate. This creates a content cluster that signals topical authority to search engines and guides users through your consideration funnel.
The Marketing Site SEO Checklist
Quick audit for any boilerplate:
[ ] Title tag: under 60 chars, includes primary keyword
[ ] Meta description: 150-160 chars, compelling, includes keyword
[ ] H1: one per page, matches page intent
[ ] Canonical URL: set on every page
[ ] robots.txt: excludes app routes
[ ] sitemap.xml: auto-generated, submitted to Google Search Console
[ ] OG tags: title, description, image for all shareable pages
[ ] JSON-LD: Article (blog), SoftwareApplication (homepage)
[ ] Core Web Vitals: LCP < 2.5s, INP < 200ms, CLS < 0.1
[ ] Internal links: blog posts link to pricing and product pages
[ ] Alt text: all images have descriptive alt text
Boilerplate SEO Out of the Box
| Boilerplate | Meta Tags | Sitemap | Structured Data | robots.txt |
|---|---|---|---|---|
| ShipFast | ✅ | ✅ | ❌ | ✅ |
| Makerkit | ✅ | ✅ | Partial | ✅ |
| T3 Stack | ❌ | ❌ | ❌ | ❌ |
| AstroWind | ✅ | ✅ | ✅ | ✅ |
| Open SaaS | ✅ | ✅ | ❌ | ✅ |
The gap between AstroWind and the Next.js boilerplates on SEO reflects the Astro framework's marketing-site focus. AstroWind was built specifically for content-heavy marketing sites and has better SEO defaults than Next.js boilerplates designed primarily for SaaS apps. If your primary need is marketing site SEO with a blog, AstroWind is worth evaluating before defaulting to a Next.js boilerplate.
Setting Up Google Search Console
All the SEO infrastructure above is invisible until you verify it's working. Google Search Console (GSC) is the essential tool for monitoring what Google sees and how it indexes your site.
Initial setup: Verify your site in GSC by adding a DNS TXT record or downloading the HTML verification file to your public/ directory. Submit your sitemap at https://yoursaas.com/sitemap.xml — GSC will start crawling within 24-48 hours.
The coverage report: GSC shows you every URL Google has crawled and why some aren't indexed. The most common issues for boilerplate-based SaaS:
- "Blocked by robots.txt": Your dashboard routes are correctly excluded. Verify this isn't accidentally catching any marketing pages.
- "Duplicate without canonical": Google found multiple versions of the same URL. Check that canonicals are correctly set on all pages.
- "Page with redirect": HTTP redirecting to HTTPS is fine; a redirect chain (HTTP → www → HTTPS → non-www) loses link equity at each hop.
- "Crawled — currently not indexed": Google crawled the page but decided not to index it. Usually thin content, duplicate content, or a page that was previously
noindexand the directive is cached.
Core Web Vitals in GSC: GSC's Core Web Vitals report shows LCP, INP, and CLS data aggregated from real user sessions (field data, not lab data). This is the authoritative source — lab tools like Lighthouse show synthetic scores that don't always match real user experience on mobile networks.
Check the Core Web Vitals report monthly. Any page marked "Poor" is a priority fix. Any page marked "Needs Improvement" is worth optimizing once the "Poor" pages are resolved.
Related Resources
For adding i18n alongside SEO — hreflang tags, locale-specific sitemaps, and RTL language support — how to add i18n to your starter kit covers the next-intl integration and how locale routing affects canonical URL structure. For waitlist and launch page SEO specifically, including pre-launch indexing and when to use noindex during early access, how to add a waitlist and launch page to your boilerplate covers the launch-phase SEO decisions. For A/B testing landing page variants without hurting SEO (canonical handling, avoiding content duplication in experiments), how to add feature flags to your SaaS starter covers the flag-based rollout pattern applicable to SEO-sensitive experiments.
Methodology
SEO recommendations based on Google Search Central documentation and the Core Web Vitals field data thresholds published by Google in 2025. Boilerplate comparison table derived from direct code review and testing of each boilerplate's SEO defaults. Structured data patterns validated against Schema.org specification and Google's Rich Results Test. Google's continued emphasis on page experience signals — particularly INP replacing FID in Core Web Vitals — reinforces why Server Components and reduced JavaScript payloads are increasingly important for SaaS marketing sites competing on organic search, making the boilerplate's rendering architecture a direct SEO factor.
Find SEO-optimized boilerplates on StarterPick.
Check out this boilerplate
View Next.json StarterPick →