Recipes
Layout + Page Merge (Next.js)
// app/layout.tsx
import { seoLayout } from "@better-seo/next"
export const metadata = seoLayout({ title: "Site" })
// app/about/page.tsx
import { seoPage } from "@better-seo/next"
export const metadata = seoPage({ title: "About" })
// Final title: uses titleTemplate from config
Route Rules
seo({
rules: [
{ match: "/blog/*", schema: [article({ ... })] },
{ match: "/app/*", meta: { robots: "noindex,nofollow" } },
{ match: "/docs/**", openGraph: { type: "article" } },
],
})
generateMetadata + Async Data
import { prepareNextSeo } from "@better-seo/next"
import { article } from "@better-seo/core"
export async function generateMetadata({ params }) {
const post = await fetchPost(params.slug)
return prepareNextSeo({
title: post.title,
description: post.excerpt,
canonical: `/blog/${post.slug}`,
openGraph: { images: [{ url: post.ogImage }] },
schema: [article({
headline: post.title,
datePublished: post.date,
url: `${site}/blog/${post.slug}`,
})],
}, { baseUrl: site })
}
OG Image Generation
npm install @better-seo/assets
import { generateOG } from "@better-seo/assets"
import { writeFile } from "node:fs/promises"
const png = await generateOG({
title: "Hello World",
siteName: "My Site",
theme: "dark",
})
await writeFile("./public/og.png", png)
CLI:
npx @better-seo/cli og "Hello World" -o ./public/og.png --site-name "Brand"
Icons + Manifest
npx @better-seo/cli icons --input ./logo.png --out ./public
Generates: favicon.ico (16/32), PNG set (16–512), apple-touch-icon, maskable icon, optional manifest.json.
MDX Frontmatter → SEO
import { fromMdx } from "@better-seo/compiler"
import { readFileSync } from "node:fs"
import { createSEO } from "@better-seo/core"
const partial = fromMdx(readFileSync("post.mdx", "utf8"))
const seo = createSEO(partial, { baseUrl: site, defaultTitle: "Blog" })
CLI:
npx @better-seo/cli content from-mdx --input ./post.mdx --out ./seo-input.json
React SPA (Vite)
import { BetterSEOHelmet, SEOProvider } from "@better-seo/react"
import { createSEO, webPage } from "@better-seo/core"
// App root
<SEOProvider config={seoConfig}>
<App />
</SEOProvider>
// Page
const seo = createSEO({ title: "Dashboard", schema: [webPage({ name: "Dashboard" })] }, config)
<BetterSEOHelmet seo={seo} />
Robots + Sitemap (Next.js)
// app/robots.ts
import { renderRobotsTxt } from "@better-seo/crawl"
export default function robots() {
return renderRobotsTxt({ sitemap: [`${process.env.SITE_URL}/sitemap.xml`] })
}
// app/sitemap.ts
import { renderSitemapXml } from "@better-seo/crawl"
export default async function sitemap() {
const urls = await getRoutes() // from your route manifest
return renderSitemapXml(urls.map(loc => ({ loc })))
}