Metadata

Learn how to add metadata to your pages for better SEO and social sharing.

What is Metadata?

Metadata provides information about your webpage to search engines, social media platforms, and browsers. In Bini.js, you can export a metadata object from any layout to control page titles, descriptions, Open Graph tags, Twitter cards, and icons.

Metadata is essential for SEO and social sharing, helping your pages look great when shared on platforms like Twitter, Facebook, and LinkedIn.

Basic Metadata

Export a metadata object from your root layout or any nested layout:

app/layout.tsx
// src/app/layout.tsx
export const metadata = {
  title: 'My Bini.js App',
  description: 'Built with Bini.js - a native React framework',
  viewport: 'width=device-width, initial-scale=1.0',
  themeColor: '#00CFFF',
  charset: 'UTF-8',
  robots: 'index, follow',
  manifest: '/site.webmanifest',
  keywords: ['react', 'vite', 'framework', 'bini'],
  authors: [{ name: 'Your Name', url: 'https://example.com' }],
  canonical: 'https://myapp.com',
}

export default function RootLayout() {
  return <Outlet />
}
FieldDescription
titlePage title shown in browser tab and search results
descriptionPage description for search results
viewportViewport configuration for responsive design
themeColorBrowser UI theme color
charsetCharacter encoding
robotsInstructions for search engine crawlers
manifestPath to web app manifest
keywordsArray or string of keywords
authorsAuthor information
canonicalCanonical URL for SEO

Open Graph

Open Graph tags control how your page appears when shared on social media platforms like Facebook, LinkedIn, and Slack.

app/about/page.tsx
// src/app/about/page.tsx
export const metadata = {
  title: 'About Us',
  description: 'Learn more about our company and team',
  openGraph: {
    title: 'About Us - My Bini.js App',
    description: 'Learn more about our company and team',
    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',
  },
}

export default function AboutPage() {
  return <h1>About Us</h1>
}
FieldDescription
titleTitle for social sharing
descriptionDescription for social sharing
urlCanonical URL for the page
typeType of content (website, article, etc.)
imagesArray of image objects for social cards
siteNameName of the site
localeLanguage locale

Twitter Cards

Twitter Cards control how your page appears when shared on Twitter/X.

app/blog/[slug]/page.tsx
// src/app/blog/[slug]/page.tsx
export const metadata = {
  title: 'Blog Post',
  description: 'A comprehensive guide to Bini.js',
  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',
    description: 'A comprehensive guide to Bini.js',
    images: ['/og-image.png'],
  },
}

export default function BlogPost() {
  return <h1>Blog Post</h1>
}
FieldDescription
cardCard type (summary, summary_large_image, app, player)
titleTitle for Twitter card
descriptionDescription for Twitter card
creatorTwitter handle of the content creator
imagesArray of image URLs for the card

Default Images

Bini.js comes with default images pre-configured. Just replace these files in your public/ directory:

public/
public/
├── favicon.ico           ← Your favicon
├── apple-touch-icon.png  ← iOS home screen icon
├── og-image.png          ← Open Graph image
├── logo.png              ← Your app logo
└── site.webmanifest      ← Web app manifest

No configuration needed. Bini.js already has all the metadata configured. Just drop your images in the public/ folder and they'll automatically be used.

Tip: For best results, use images that are at least 1200x630 pixels for Open Graph images.

Icons

Define favicons, Apple touch icons, and other icons for your application.

app/layout.tsx
// src/app/layout.tsx
export const metadata = {
  title: 'My App',
  icons: {
    icon: [
      { url: '/favicon.svg', type: 'image/svg+xml' },
      { url: '/favicon.ico' },
      { url: '/favicon-32x32.png', sizes: '32x32' },
      { url: '/favicon-16x16.png', sizes: '16x16' },
    ],
    shortcut: '/favicon.ico',
    apple: [
      { url: '/apple-touch-icon.png', sizes: '180x180' },
      { url: '/apple-touch-icon-precomposed.png' },
    ],
  },
}

export default function RootLayout() {
  return <Outlet />
}
FieldDescription
iconStandard favicon (array of icon objects)
shortcutShortcut icon URL
appleApple touch icons (array of icon objects)

Nested Metadata

Nested layouts can export their own metadata. Page titles are automatically combined using the template defined in the root layout.

// src/app/layout.tsx - Root layout
export const metadata = {
  title: {
    default: 'My App',
    template: '%s | My App',
  },
  description: 'Built with Bini.js',
}

// src/app/blog/layout.tsx - Blog layout
export const metadata = {
  title: 'Blog',
  description: 'Blog posts about Bini.js',
}

// src/app/blog/[slug]/page.tsx - Blog post
export const metadata = {
  title: 'Getting Started with Bini.js',
  // Result: "Getting Started with Bini.js | My App"
  description: 'Learn how to get started with Bini.js',
}

When nested layouts export metadata, the title is automatically combined with the root layout's template. Other fields like description, openGraph, and twitter override ancestor values.