brease-next Package
SEO & Metadata
The brease-next package provides functions and components for generating SEO metadata, robots.txt, sitemaps, structured data, and custom code injection -- all driven by data managed in the Brease CMS.
generateBreasePageMetadata
Generates a Next.js Metadata object from a BreasePage object. This is the primary way to set page-level SEO tags.
Important: This function takes a page object (the result of fetchPage), not a slug string.
Signature
function generateBreasePageMetadata(
page: BreasePage,
options?: { metadataBase?: string | URL }
): Metadata
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | BreasePage | Yes | The page object from fetchPage |
options | { metadataBase?: string | URL } | No | Base URL for resolving relative URLs in Open Graph images, canonical URLs, etc. |
Generated Metadata Fields
| Metadata Field | Source | Fallback |
|---|---|---|
title | page.metaTitle | page.name |
description | page.metaDescription | -- |
robots.index | page.indexing | -- |
robots.follow | page.indexing | -- |
alternates.canonical | page.canonicalUrl | -- |
alternates.languages | page.alternateLinks | -- |
openGraph.url | page.openGraph.url | -- |
openGraph.type | page.openGraph.type | -- |
openGraph.title | page.openGraph.title | -- |
openGraph.description | page.openGraph.description | -- |
openGraph.images | page.openGraph.image | -- |
twitter.site | page.twitterCard.site | -- |
twitter.card | page.twitterCard.type | -- |
twitter.title | page.twitterCard.title | -- |
twitter.description | page.twitterCard.description | -- |
twitter.creator | page.twitterCard.creator | -- |
twitter.images | page.twitterCard.image | -- |
Usage
// src/app/[[...slug]]/page.tsx
import { generateBreasePageMetadata } from 'brease-next'
import { getPage } from '@/lib/brease/get-page'
import type { Metadata } from 'next'
type Props = { params: Promise<{ slug?: string[] }> }
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const pageSlug = slug ? slug.join('/') : ''
const result = await getPage(pageSlug)
if (!result.success) return {}
return generateBreasePageMetadata(result.data, {
metadataBase: 'https://example.com',
})
}
generateBreaseRobots
Generates a robots.txt configuration object for the Next.js Metadata API.
Signature
function generateBreaseRobots(
siteUrl: string,
options?: GenerateBreaseRobotsOptions
): MetadataRoute.Robots
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
siteUrl | string | Yes | Your site's public URL (e.g. "https://example.com") |
options | GenerateBreaseRobotsOptions | No | Override default rules, sitemap, or host |
interface GenerateBreaseRobotsOptions {
rules?: MetadataRoute.Robots['rules']
sitemap?: string | string[]
host?: string
}
Default Behavior
Without options, the function generates:
- rules: Allow all user agents on all paths
- sitemap:
{siteUrl}/sitemap.xml
Usage
// src/app/robots.ts
import { generateBreaseRobots } from 'brease-next'
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return generateBreaseRobots('https://example.com')
}
With custom options:
// src/app/robots.ts
import { generateBreaseRobots } from 'brease-next'
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return generateBreaseRobots('https://example.com', {
rules: [
{ userAgent: '*', allow: '/' },
{ userAgent: 'Googlebot', allow: '/', disallow: '/private/' },
],
sitemap: [
'https://example.com/sitemap.xml',
'https://example.com/blog-sitemap.xml',
],
host: 'https://example.com',
})
}
generateSitemap
Fetches sitemap data from the Brease CMS API. Returns data in the format expected by Next.js MetadataRoute.Sitemap.
Signature
function generateSitemap(): Promise<BreaseResponse<MetadataRoute.Sitemap>>
Usage
// src/app/sitemap.ts
import { generateSitemap } from 'brease-next'
import type { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const result = await generateSitemap()
return result.success ? result.data : []
}
The CMS controls which pages appear in the sitemap based on the indexing toggle on each page. Pages with indexing disabled are excluded.
BreaseStructuredData
Server component that renders JSON-LD structured data from page.structuredData.
How It Works
- Reads the
structuredDatafield from the page object (an array of JSON-LD objects) - Renders each object as a
<script type="application/ld+json">tag - Renders nothing if
structuredDataisnullor an empty array
Usage
import { BreaseStructuredData, ensureSuccess, fetchPage } from 'brease-next'
export default async function Page() {
const page = ensureSuccess(await fetchPage('about-us'))
return (
<>
<BreaseStructuredData page={page} />
{/* page content */}
</>
)
}
Structured data is managed per page in the CMS under the page's SEO settings. Common JSON-LD schemas include:
- Organization -- company info, logo, contact
- Article -- blog posts, news articles
- Product -- e-commerce product data
- FAQ -- frequently asked questions
- BreadcrumbList -- breadcrumb navigation
BreaseCustomCode
Server component that renders custom HTML and scripts from page.customCode.
How It Works
- Reads the
customCodefield from the page object (a string of HTML/script content) - Renders the content using
dangerouslySetInnerHTML - Renders nothing if
customCodeisnullor empty
Usage
import { BreaseCustomCode, ensureSuccess, fetchPage } from 'brease-next'
export default async function Page() {
const page = ensureSuccess(await fetchPage('about-us'))
return (
<>
{/* page content */}
<BreaseCustomCode page={page} />
</>
)
}
Custom code is managed per page in the CMS page settings. Use cases include page-specific analytics events, third-party widget scripts, or embedded content.
For site-wide scripts, use BreaseSite.customCode (available via fetchSite()).
Page-Level SEO Fields
These fields are managed in the CMS page editor and drive the metadata generation:
Core SEO
| Field | Type | Description |
|---|---|---|
metaTitle | string | null | The <title> tag. Falls back to page name if not set |
metaDescription | string | null | The meta description tag |
canonicalUrl | string | null | Canonical URL for the page |
indexing | boolean | Controls robots meta tag. When false, page is noindex/nofollow |
Open Graph
| Field | Type | Description |
|---|---|---|
openGraph.url | string | null | og:url |
openGraph.type | string | null | og:type (e.g. "website", "article") |
openGraph.image | string | null | og:image URL |
openGraph.title | string | null | og:title |
openGraph.description | string | null | og:description |
Twitter Card
| Field | Type | Description |
|---|---|---|
twitterCard.site | string | null | twitter:site handle |
twitterCard.type | string | null | Card type (e.g. "summary_large_image") |
twitterCard.image | string | null | twitter:image URL |
twitterCard.title | string | null | twitter:title |
twitterCard.creator | string | null | twitter:creator handle |
twitterCard.description | string | null | twitter:description |
Advanced
| Field | Type | Description |
|---|---|---|
structuredData | object[] | null | Array of JSON-LD objects for structured data |
customCode | string | null | Arbitrary HTML/script injection |
alternateLinks | Record<string, string> | null | Locale-to-URL mapping for hreflang tags |
Complete Setup Example
Here is a full example with all SEO features configured:
robots.ts:
// src/app/robots.ts
import { generateBreaseRobots } from 'brease-next'
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return generateBreaseRobots('https://example.com')
}
sitemap.ts:
// src/app/sitemap.ts
import { generateSitemap } from 'brease-next'
import type { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const result = await generateSitemap()
return result.success ? result.data : []
}
Page with metadata:
// src/app/[[...slug]]/page.tsx
import {
BreasePage,
BreaseStructuredData,
BreaseCustomCode,
generateBreasePageMetadata,
ensureSuccess,
} from 'brease-next'
import { sectionMap } from '@/lib/brease/brease-config'
import { getPage } from '@/lib/brease/get-page'
import { notFound } from 'next/navigation'
import type { Metadata } from 'next'
type Props = { params: Promise<{ slug?: string[] }> }
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const pageSlug = slug ? slug.join('/') : ''
const result = await getPage(pageSlug)
if (!result.success) return {}
return generateBreasePageMetadata(result.data, {
metadataBase: 'https://example.com',
})
}
export default async function Page({ params }: Props) {
const { slug } = await params
const pageSlug = slug ? slug.join('/') : ''
const result = await getPage(pageSlug)
if (!result.success) {
if (result.status === 404) return notFound()
throw new Error(result.error)
}
const page = result.data
return (
<>
<BreaseStructuredData page={page} />
<BreasePage page={page} sectionMap={sectionMap} />
<BreaseCustomCode page={page} />
</>
)
}
Next Steps
- API Reference -- full function signatures and types
- Components -- all component props and usage
- Preview Integration -- live preview from the CMS