Metadata
Export metadata from layouts and pages for SEO and social sharing. Consumed by bini-ssg at build time.
Overview
Metadata describes your page to search engines, social platforms, and browsers. Export a metadata object from any layout or page for titles, descriptions, Open Graph, Twitter cards, and icons.
bini-ssg reads route metadata via getMetadataForRoute and injects it into each pre-rendered page head during vite build.
| Feature | How bini-ssg uses it |
|---|---|
| title, description, robots, canonical | Injected as title and meta tags |
| icons | icon, shortcut, apple-touch-icon |
| openGraph | og:title, og:type, og:description, og:url, og:image |
| twitter:card, twitter:title, twitter:description, twitter:image |
What is Metadata?
Metadata controls how links look when shared on Twitter, Facebook, LinkedIn, and Slack. You author it in route and layout files. The router merges layout-level metadata before bini-ssg sees it.
getMetadataForRoute returns the already-merged entry for a route. bini-ssg does not invent metadata - it only injects what you export.Basic Metadata
Export metadata from the root layout or any nested layout or page.
export const metadata = {
title: 'My Bini.js App',
description: 'Built with Bini.js - a native React framework',
robots: 'index, follow',
canonical: 'https://myapp.com',
themeColor: '#0a0a0a',
keywords: ['react', 'vite', 'framework', 'bini'],
}| Field | Description |
|---|---|
| title | Document title |
| description | Meta description |
| robots | Crawler instructions |
| canonical | Canonical URL |
| themeColor | Browser UI color |
| keywords | Optional keyword list |
Open Graph
Open Graph tags control previews on Facebook, LinkedIn, and Slack.
export const metadata = {
title: 'About Us',
description: 'Learn more about our company',
openGraph: {
title: 'About Us - My Bini.js App',
description: 'Learn more about our company',
url: 'https://myapp.com/about',
type: 'website',
images: [
{
url: '/og-image.png',
width: 1200,
height: 630,
alt: 'About Us',
},
],
siteName: 'My Bini.js App',
locale: 'en_US',
},
}Twitter Cards
Twitter (X) card fields control how links appear in the feed.
export const metadata = {
title: 'Blog Post',
twitter: {
card: 'summary_large_image',
title: 'Blog Post - My Bini.js App',
description: 'A comprehensive guide to Bini.js',
creator: '@bini_js',
images: ['/og-image.png'],
},
openGraph: {
title: 'Blog Post',
images: ['/og-image.png'],
},
}Default Images
Put static assets in public/. Reference them by absolute path in metadata.
public/ are served as-is.Icons
export const metadata = {
icons: {
icon: [
{ url: '/favicon.svg', type: 'image/svg+xml' },
{ url: '/favicon.ico' },
],
apple: [{ url: '/apple-touch-icon.png', sizes: '180x180' }],
},
}Nested Metadata
Layout and page metadata merge. Use a title template at the root so child pages can set a short title.
export const metadata = {
title: {
default: 'My App',
template: '%s | My App',
},
}export const metadata = {
title: 'Getting Started with Bini.js',
// Result: "Getting Started with Bini.js | My App"
}bini-ssg Injection
During vite build, bini-ssg merges metadata into static HTML.
- SEO fields: title, description, icons, Open Graph, Twitter - existing matching tags updated in place
- Head tree: element / text / raw nodes (raw for JSON-LD)
- Dynamic routes: metadata is keyed by the route pattern (e.g.
/blog/:slug), not each concrete URL
Complete Example
export const metadata = {
title: 'How bini-ssg pre-renders routes',
description:
'A look at link crawling, shells, and metadata injection.',
robots: 'index, follow',
canonical: 'https://example.com/blog/how-bini-ssg-works',
openGraph: {
title: 'How bini-ssg pre-renders routes',
type: 'article',
images: ['https://example.com/og/how-bini-ssg-works.png'],
},
twitter: {
card: 'summary_large_image',
creator: '@bini_js',
},
}