Spacerr
  • Features
  • Pricing
  • FAQ
  • Docs
Get Access
Spacerr
  • Introduction
  • Features
  • Tech Stack
  • Setup
  • Configuration
  • Agents
  • Database
  • Jobs
  • Admin
  • Settings
  • Billing
  • Storage
  • Email
  • Support
  • Localization
    • Overview
    • Publishing
    • Blog SEO
  • SEO
  • Analytics
  • UI And Navigation
  • Deploying To Production
  • Testing And QA
  • Troubleshooting

Search documentation

Search documentation pages.

Documentation/Blog SEO

Blog SEO

The blog is wired into the SEO system. Blog pages generate metadata from stored posts, use explicit canonical URLs, render JSON LD, appear in the sitemap, and feed RSS readers.

Canonical URLs

Blog URL helpers live in src/features/blog/utils/blog-post-seo.ts.

txt
export function getBlogPostCanonicalUrl(slug: string) {
  return `${siteOrigin}${WebRoutes.blogPost.path}/${slug}`
}

Use stable, readable slugs. A published post URL should not change unless you are ready to handle redirects.

Post Metadata

The post page builds metadata from the stored post.

typescript
return {
  title: post.title,
  description: post.preview,
  keywords: post.seoKeywords,
  alternates: {
    canonical,
  },
  openGraph: {
    type: "article",
    title: post.title,
    description: post.preview,
    url: canonical,
    images: [{ url: imageUrl, width: 1200, height: 630, alt: post.title }],
  },
}

Use title, preview, seoKeywords, and imageSrc carefully. Those fields control the post headline, meta description, metadata keywords, social preview image, and RSS output.

Missing Posts

If a blog post cannot be found, the route returns noindex metadata.

typescript
return createNoIndexMetadata("Post not found", "The requested blog post could not be found.")

This keeps missing or deleted content out of the index.

JSON LD

Blog posts render BlogPosting JSON LD through src/features/blog/components/blog-post-article-json-ld.tsx.

typescript
const schema = {
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  headline,
  description,
  image: resolveAbsoluteUrl(imageSrc),
  datePublished: datePublished.toISOString(),
  dateModified: dateModified.toISOString(),
  author: {
    "@type": "Person",
    name: authorName,
  },
  publisher: {
    "@type": "Organization",
    name: SiteConfig.name,
  },
}

The script is escaped before rendering, so structured data stays safe even when post fields come from the database.

Sitemap

The sitemap includes the blog index and every published blog post.

typescript
const blogRoutes = posts.map((post) => ({
  url: getBlogPostCanonicalUrl(post.slug),
  lastModified: post.updatedAt,
  changeFrequency: "monthly",
  priority: 0.7,
}))

Sitemap generation lives in src/app/sitemap.ts.

RSS

The RSS feed lives at /rss.xml.

typescript
const posts = await listBlogPosts(RSS_FEED_LIMIT, 0)

const postUrl = WebRoutes.blogPost.withBaseUrl(post.slug)
const description = escapeXml(post.preview)
const categoryXml = post.seoKeywords.map((keyword) => `<category>${escapeXml(keyword)}</category>`).join("")

The feed uses the post preview as the item description and SEO keywords as RSS categories. The route returns application/rss+xml and uses cache headers for public feed readers.

Cover Images

Blog cover images should be public and sized for social cards.

  • Use a 1200 by 630 image when possible.
  • Store public blog covers through the public Vercel Blob token.
  • Keep the cover image relevant to the post.
  • Avoid placeholder images for published content.

The same image can appear on the post page, blog cards, Open Graph previews, Twitter cards, and RSS readers.

Where To Customize

Use these files first:

  • src/features/blog/utils/blog-post-seo.ts for canonical URLs and image URL resolution.
  • src/app/(app)/(content)/blog/[slug]/page.tsx for post metadata.
  • src/features/blog/components/blog-post-article-json-ld.tsx for article structured data.
  • src/app/sitemap.ts for sitemap inclusion.
  • src/app/rss.xml/route.ts for RSS feed output.
Blog Publishing

Learn how blog publishing works in Spacerr.

SEO

Learn how metadata, structured data, sitemap, robots, RSS, and AI discovery files are structured.

On this page
Canonical URLsPost MetadataMissing PostsJSON LDSitemapRSSCover ImagesWhere To Customize