webhouse.appwebhouse.appdocs

Drop-in sitemap, robots.txt, llms.txt, metadata, JSON-LD, RSS feed, and static params — all auto-generated from CMS content via @webhouse/cms/next.

Overview

@webhouse/cms/next is a sub-path export that gives your Next.js site full SEO and discoverability — sitemap, robots.txt, llms.txt, metadata, JSON-LD, RSS feed — all auto-generated from CMS content and _seo fields.

No new logic needed. It wraps the existing CMS build pipeline for Next.js consumption.

bash
# Already included with @webhouse/cms — no extra install
import { cmsSitemap, cmsRobots, cmsMetadata } from '@webhouse/cms/next';

Sitemap

Auto-generates sitemap.xml with hreflang alternates for multi-locale sites.

typescript
// app/sitemap.ts
import { cmsSitemap } from '@webhouse/cms/next';

export default cmsSitemap({
  baseUrl: 'https://example.com',
  collections: [
    { name: 'pages', urlPrefix: '/' },
    { name: 'posts', urlPrefix: '/blog' },
  ],
  // Optional i18n
  locales: ['en', 'da'],
  defaultLocale: 'en',
  localeStrategy: 'prefix-other',
});

Options:

OptionTypeDefaultDescription
baseUrlstringSite URL (no trailing slash)
collectionsSitemapCollection[]Collections to include
localesstring[]Available locales for hreflang
defaultLocalestringDefault locale (gets x-default)
localeStrategystring"prefix-other"URL locale strategy
changeFrequencystring"weekly"Default change frequency
defaultPrioritynumber0.7Default priority

Robots.txt

Generates robots.txt with AI bot management strategies from F112 GEO.

typescript
// app/robots.ts
import { cmsRobots } from '@webhouse/cms/next';

export default cmsRobots({
  baseUrl: 'https://example.com',
  strategy: 'maximum',  // or 'balanced', 'restrictive', 'custom'
});

Strategies:

StrategyBehavior
maximumAllow all bots including AI crawlers
balancedAllow search engines, block aggressive AI scrapers
restrictiveBlock all AI bots, allow only search engines
customYour own rules via customRules

llms.txt

Machine-readable site index for AI agents — helps AI crawlers understand your site structure.

typescript
// app/llms.txt/route.ts
import { cmsLlmsTxt } from '@webhouse/cms/next';

export const GET = cmsLlmsTxt({
  baseUrl: 'https://example.com',
  siteTitle: 'My Site',
  siteDescription: 'A great site built with webhouse.app',
  collections: [
    { name: 'posts', label: 'Blog Posts', urlPrefix: '/blog' },
  ],
});

For the full content export (all document text):

typescript
// app/llms-full.txt/route.ts
import { cmsLlmsFullTxt } from '@webhouse/cms/next';

export const GET = cmsLlmsFullTxt({
  baseUrl: 'https://example.com',
  siteTitle: 'My Site',
  collections: [{ name: 'posts', label: 'Blog Posts', urlPrefix: '/blog' }],
});

Metadata

Extracts _seo fields from any CMS document into a Next.js Metadata object.

typescript
// app/blog/[slug]/page.tsx
import { cmsMetadata } from '@webhouse/cms/next';
import { getDocument } from '@/lib/content';

export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const doc = getDocument('posts', slug);
  if (!doc) return {};
  return cmsMetadata({
    baseUrl: 'https://example.com',
    siteName: 'My Site',
    doc,
    collection: 'posts',
    urlPrefix: '/blog',
  });
}

What it generates:

  • title from _seo.metaTitle or data.title
  • description from _seo.metaDescription or data.excerpt
  • keywords from _seo.keywords
  • openGraph with image, site name, type (article/website), published time
  • alternates.canonical from _seo.canonical or computed URL
  • robots from _seo.robots
  • Geo meta tags from map fields (F96)

JSON-LD

Extracts structured data from _seo.jsonLd for search engine rich results.

typescript
// In your page component
import { cmsJsonLd } from '@webhouse/cms/next';

export default function BlogPost({ doc }) {
  const jsonLd = cmsJsonLd(doc);
  return (
    <article>
      {jsonLd && (
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
        />
      )}
      <h1>{doc.data.title}</h1>
    </article>
  );
}

CMS admin generates JSON-LD from 12 schema templates (Article, BlogPosting, FAQ, Product, LocalBusiness, etc.) via the SEO panel.

RSS Feed

Auto-generates RSS 2.0 XML feed from CMS content.

typescript
// app/feed.xml/route.ts
import { cmsFeed } from '@webhouse/cms/next';

export const GET = cmsFeed({
  baseUrl: 'https://example.com',
  title: 'My Blog',
  description: 'Latest posts from My Blog',
  collections: [{ name: 'posts', urlPrefix: '/blog' }],
  maxItems: 50,
});

generateStaticParams

Factory for Next.js generateStaticParams() — returns all published slugs for a collection.

typescript
// app/blog/[slug]/page.tsx
import { cmsGenerateStaticParams } from '@webhouse/cms/next';

export const generateStaticParams = cmsGenerateStaticParams({
  collection: 'posts',
  paramName: 'slug',  // default
});

Fly.io Deployment

Next.js boilerplates include a production-ready Dockerfile for Fly.io deploy:

bash
# Deploy via CLI
flyctl deploy --remote-only --ha=false

Or use the Deploy tab in CMS admin — it auto-detects the Dockerfile and deploys to Fly.io with:

  • Region: arn (Stockholm)
  • Port: 3000
  • Memory: 512MB
  • Auto-generated fly.toml

The Dockerfile uses Next.js standalone output (output: "standalone" in next.config.ts) for minimal image size. Content files are copied into the image for fs-based reads at runtime.

Complete Setup

Here's what a fully SEO-optimized Next.js site looks like:

app/
  sitemap.ts          ← cmsSitemap()
  robots.ts           ← cmsRobots()
  llms.txt/route.ts   ← cmsLlmsTxt()
  llms-full.txt/route.ts ← cmsLlmsFullTxt()
  feed.xml/route.ts   ← cmsFeed()
  blog/
    [slug]/page.tsx   ← cmsMetadata() + cmsJsonLd()
  [slug]/page.tsx     ← cmsMetadata() + cmsJsonLd()

All of this is pre-configured in both the nextjs-boilerplate and nextjs-github-boilerplate templates.

Tags:Next.jsSEOFrameworks
Previous
Next.js Integration Guide
Next
Side-by-Side Translation Editing
JSON API →Edit on GitHub →