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.

FeatureHow bini-ssg uses it
title, description, robots, canonicalInjected as title and meta tags
iconsicon, shortcut, apple-touch-icon
openGraphog:title, og:type, og:description, og:url, og:image
twittertwitter: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.

app/layout.tsx
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'],
}
FieldDescription
titleDocument title
descriptionMeta description
robotsCrawler instructions
canonicalCanonical URL
themeColorBrowser UI color
keywordsOptional keyword list

Open Graph

Open Graph tags control previews on Facebook, LinkedIn, and Slack.

app/about/page.tsx
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.

app/blog/[slug]/page.tsx
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
favicon.ico
apple-touch-icon.png
og-image.png
logo.png
site.webmanifest
Recommended Open Graph size is 1200×630. No extra config - files in public/ are served as-is.

Icons

app/layout.tsx
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.

app
layout.tsx
page.tsx
blog
layout.tsx
page.tsx
[slug]
page.tsx
/
/blog
/blog/:slug
app/layout.tsx
export const metadata = {
  title: {
    default: 'My App',
    template: '%s | My App',
  },
}
app/blog/[slug]/page.tsx
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

app/blog/[slug]/page.tsx
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',
  },
}
Was this helpful?