BunPress Documentation
⌘ K

SEO Features

BunPress includes comprehensive SEO features to ensure your documentation ranks well in search engines and provides rich previews when shared on social media.

Overview

All SEO features are automatically enabled and work out of the box with sensible defaults. Advanced customization is available through the configuration file.

Automatic SEO Features

  • XML Sitemap - Auto-generated sitemap.xml
  • Robots.txt - Configurable robots.txt file
  • Meta Tags - Title, description, and viewport tags
  • Open Graph - Facebook, LinkedIn, and social media previews
  • Twitter Cards - Enhanced Twitter previews
  • Canonical URLs - Prevent duplicate content issues
  • Structured Data - JSON-LD for search engines
  • RSS Feeds - Blog-style documentation feeds
  • SEO Validation - Built-in CLI tool for checking SEO health

---

XML Sitemap

BunPress automatically generates a comprehensive XML sitemap for all your documentation pages.

Basic Configuration

// bunpress.config.ts
export default {
  sitemap: {
    enabled: true,  // Enable sitemap generation
    baseUrl:'https://docs.example.com' 'https://docs.example.com',// Required: your site's URL  // Required: your site's URL
    filename:'sitemap.xml' 'sitemap.xml',  // Output filename
  }
}

Advanced Configuration

export default {
  sitemap: {
    enabled: true,
    baseUrl:'https://docs.example.com' 'https://docs.example.com',

    // Default values for all pages
    defaultPriority: 0.5,  // 0.0 to 1.0
    defaultChangefreq:'monthly' 'monthly',  // always, hourly, daily, weekly, monthly, yearly, never

    // Custom priority for specific paths
    priorityMap: {'/'
      '/': 1.0,  // Homepage highest priority'/guide/*'
      '/guide/*': 0.8,  // All guide pages'/api/*'
      '/api/*': 0.7,  // API documentation'/examples/*'
      '/examples/*': 0.6,  // Examples
    },

    // Custom changefreq for specific paths
    changefreqMap: {'/changelog'
      '/changelog':'daily' 'daily',  // Frequently updated'/blog/*'
      '/blog/*':'weekly' 'weekly',  // Blog posts'/guide/*'
      '/guide/*':'monthly' 'monthly',  // Stable documentation
    },

    // Exclude specific paths
    exclude: ['/drafts/*'
      '/drafts/*',  // Draft pages'/internal/*'
      '/internal/*',  // Internal docs'/test'
      '/test',  // Test pages
    ],

    // For large sites (50,000+ URLs)
    maxUrlsPerFile: 50000,
    useSitemapIndex: true,  // Generate sitemap index

    // Transform URLs before adding to sitemap
    transform: (entry) => {
      // Modify or filter sitemap entries
      if (entry.url.includes('deprecated''deprecated')) {
        return null;  // Exclude from sitemap
      }
      return entry;
    },

    verbose: true  // Show generation details
  }
}

Pattern Matching

The priorityMap, changefreqMap, and exclude options support glob patterns:

  • * - Matches any characters except /
  • ** - Matches any characters including /
  • ? - Matches single character

Examples:

priorityMap: {'/guide'
  '/guide': 0.9,           // Exact match'/guide/*'
  '/guide/*': 0.8,         // Direct children'/guide/**'
  '/guide/**': 0.7,        // All descendants'/api/v?/*'
  '/api/v?/*': 0.6,        // /api/v1/*, /api/v2/*
}

Generated Sitemap

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://docs.example.com/</loc>
    <lastmod>2024-10-29</lastmod>
    <changefreq>monthly</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://docs.example.com/guide</loc>
    <lastmod>2024-10-28</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>
  <!-- More URLs... -->
</urlset>

Sitemap Index

For large documentation sites with over 50,000 pages:

export default {
  sitemap: {
    enabled: true,
    baseUrl:'https://docs.example.com' 'https://docs.example.com',
    maxUrlsPerFile: 50000,
    useSitemapIndex: true
  }
}

Generates:

  • sitemap.xml - Sitemap index file
  • sitemap-1.xml - First 50,000 URLs
  • sitemap-2.xml - Next 50,000 URLs
  • etc.

---

Robots.txt

Configure how search engines crawl your documentation.

Basic Configuration

export default {
  robots: {
    enabled: true,
    filename:'robots.txt' 'robots.txt'
  }
}

Advanced Configuration

export default {
  robots: {
    enabled: true,
    filename:'robots.txt' 'robots.txt',

    // Define rules for different user agents
    rules: [
      {
        userAgent:'*' '*',  // All bots
        allow: ['/''/'],
        disallow: ['/drafts/'
          '/drafts/','/internal/'
          '/internal/','/private/'
          '/private/'
        ],
        crawlDelay: 10  // Seconds between requests
      },
      {
        userAgent:'Googlebot' 'Googlebot',  // Google specifically
        allow: ['/''/'],
        disallow: ['/drafts/''/drafts/']
        // No crawl delay for Google
      },
      {
        userAgent:'Bingbot' 'Bingbot',
        allow: ['/''/'],
        crawlDelay: 5
      }
    ],

    // Link to sitemap
    sitemaps: ['https://docs.example.com/sitemap.xml'
      'https://docs.example.com/sitemap.xml'
    ],

    // Host directive
    host:'https://docs.example.com' 'https://docs.example.com',

    // Custom content to append
    customContent: `
# Custom rules
User-agent: BadBot
Disallow: /
    `
  }
}

Generated Robots.txt

User-agent: *
Allow: /
Disallow: /drafts/
Disallow: /internal/
Crawl-delay: 10

User-agent: Googlebot
Allow: /
Disallow: /drafts/

User-agent: Bingbot
Allow: /
Crawl-delay: 5

Sitemap: https://docs.example.com/sitemap.xml
Host: https://docs.example.com

---

Meta Tags

BunPress automatically generates proper meta tags for every page.

Basic Meta Tags

Configured in bunpress.config.ts:

export default {
  markdown: {
    title:'BunPress Documentation' 'BunPress Documentation',
    meta: {
      description:'Fast, modern documentation engine powered by Bun' 'Fast, modern documentation engine powered by Bun',
      generator:'BunPress' 'BunPress',
      viewport:'width=device-width, initial-scale=1.0' 'width=device-width, initial-scale=1.0',
      // Add custom meta tags'theme-color'
      'theme-color':'#5672cd' '#5672cd','twitter:site'
      'twitter:'@stacksjs'site': '@stacksjs'
    }
  }
}

Page-Level Meta Tags

Override in frontmatter:

---
title: Getting Started with BunPress
description: Learn how to create beautiful documentation in minutes
---

# Getting Started

Generated Meta Tags

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Getting Started with BunPress</title>
  <meta name="description" content="Learn how to create beautiful documentation in minutes">
  <meta name="generator" content="BunPress">

  <!-- Canonical URL -->
  <link rel="canonical" href="https://docs.example.com/getting-started">

  <!-- Open Graph -->
  <meta property="og:type" content="website">
  <meta property="og:url" content="https://docs.example.com/getting-started">
  <meta property="og:title" content="Getting Started with BunPress">
  <meta property="og:description" content="Learn how to create beautiful documentation in minutes">
  <meta property="og:site_name" content="BunPress Documentation">

  <!-- Twitter Card -->
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="Getting Started with BunPress">
  <meta name="twitter:description" content="Learn how to create beautiful documentation in minutes">
</head>

---

Open Graph Tags

Provide rich previews when sharing on social media.

Configuration

export default {
  markdown: {
    meta: {
      // Open Graph'og:site_name'
      'og:'BunPress Documentation'site_name': 'BunPress Documentation','og:image'
      'og:'https://docs.example.com/images/social-card.png'image': 'https://docs.example.com/images/social-card.png','og:image:width'
      'og:'1200'image:width': '1200','og:image:height'
      'og:'630'image:height': '630','og:image:alt'
      'og:'BunPress - Fast Documentation Engine'image:alt': 'BunPress - Fast Documentation Engine'
    }
  }
}

Social Card Image

Create a 1200x630px image for social previews:

docs/public/images/social-card.png  (1200x630)

Page-Specific Images

---
title: API Reference
description: Complete API documentation
image: /images/api-social-card.png
---

Preview Examples

Facebook/LinkedIn:

[Large Image: 1200x630]
BunPress Documentation
Getting Started with BunPress
Learn how to create beautiful documentation in minutes
docs.example.com

Discord/Slack:

[Thumbnail: 200x200]
Getting Started with BunPress
Learn how to create beautiful documentation in minutes
docs.example.com

---

Twitter Cards

Enhanced Twitter previews with card types.

Configuration

export default {
  markdown: {
    meta: {'twitter:card'
      'twitter:'summary_large_image'card': 'summary_large_image',// or 'summary''twitter:site'  // or 'summary'
      'twitter:'@stacksjs'site': '@stacksjs','twitter:creator'
      'twitter:'@username'creator': '@username','twitter:image'
      'twitter:'https://docs.example.com/images/twitter-card.png'image': 'https://docs.example.com/images/twitter-card.png'
    }
  }
}

Card Types

Summary Large Image (recommended):

  • 1200x628px image
  • Large preview
  • Best for visual content
  • 'twitter:card''twitter:'summary_large_image'card': 'summary_large_image'

Summary (compact):

  • 120x120px image
  • Small thumbnail
  • Compact preview
  • 'twitter:card''twitter:'summary'card': 'summary'

---

Canonical URLs

Prevent duplicate content penalties by specifying the canonical version of each page.

Automatic Canonical URLs

BunPress automatically generates canonical URLs based on your sitemap.baseUrl:

export default {
  sitemap: {
    baseUrl:'https://docs.example.com' 'https://docs.example.com'
  }
}

Generated:

<link rel="canonical" href="https://docs.example.com/guide/getting-started">

Custom Canonical URLs

Override in frontmatter:

---
title: Deployment Guide
canonical: https://main-docs.example.com/deployment
---

---

Structured Data (JSON-LD)

Help search engines understand your content structure with JSON-LD markup.

Automatic Schemas

BunPress generates appropriate schemas automatically:

TechArticle Schema

For documentation pages:

{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "Getting Started with BunPress",
  "description": "Learn how to create beautiful documentation",
  "datePublished": "2024-01-15",
  "dateModified": "2024-10-29",
  "author": {
    "@type": "Organization",
    "name": "Stacks.js"
  },
  "publisher": {
    "@type": "Organization",
    "name": "BunPress Documentation"
  }
}

For navigation hierarchy:

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://docs.example.com/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Guide",
      "item": "https://docs.example.com/guide"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Getting Started",
      "item": "https://docs.example.com/guide/getting-started"
    }
  ]
}

WebSite Schema

For homepage:

{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "BunPress Documentation",
  "url": "https://docs.example.com",
  "description": "Fast, modern documentation engine powered by Bun"
}

---

RSS Feeds

Generate RSS feeds for blog-style documentation updates.

Configuration

export default {
  rss: {
    enabled: true,
    title:'BunPress Updates' 'BunPress Updates',
    description:'Latest documentation updates and releases' 'Latest documentation updates and releases',
    author:'BunPress Team' 'BunPress Team',
    email:'team@bunpress.dev' 'team@bunpress.dev',
    language:'en-us' 'en-us',
    filename:'feed.xml' 'feed.xml',
    maxItems: 20,
    fullContent: false  // Include full content or excerpts
  }
}

Page Requirements

Add date to frontmatter for RSS inclusion:

---
title: Announcing BunPress v2.0
description: Major release with new features
date: 2024-10-29
author: Chris Breuer
---

# Announcing BunPress v2.0

Content here...

Generated Feed

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>BunPress Updates</title>
    <description>Latest documentation updates</description>
    <link>https://docs.example.com</link>
    <language>en-us</language>
    <lastBuildDate>Tue, 29 Oct 2024 10:00:00 GMT</lastBuildDate>

    <item>
      <title>Announcing BunPress v2.0</title>
      <link>https://docs.example.com/blog/v2-announcement</link>
      <guid>https://docs.example.com/blog/v2-announcement</guid>
      <description>Major release with new features</description>
      <pubDate>Tue, 29 Oct 2024 09:00:00 GMT</pubDate>
      <author>Chris Breuer</author>
    </item>
  </channel>
</rss>

---

SEO Validation

BunPress includes a built-in SEO checker to identify issues.

Run SEO Check

bunpress seo:check

What It Checks

1. Page Titles

  • All pages have titles
  • Optimal length (10-60 characters)
  • No duplicate titles

2. Meta Descriptions

  • All pages have descriptions
  • Optimal length (50-160 characters)
  • Unique descriptions

3. Internal Links

  • No broken links
  • All references resolve

4. Images

  • All images have alt text
  • Alt text is descriptive

Example Output

$ bunpress seo:check

SEO Validation Results

Checked: 23 pages

Errors (3):
   guide/advanced.md: Missing meta description
   api/endpoints.md: Title too long (67 chars, max 60)
   tutorial.md: Broken link: /missing-page

Warnings (2):
   config.md: Description too short (35 chars, min 50)
   examples.md: Image missing alt text (line 45)

Summary:
  Titles:        23/23 
  Descriptions:  21/23  (91%)
  Links:         22/23  (96%)
  Images:        45/46  (98%)

Run with --fix to automatically resolve some issues.

Auto-Fix Issues

bunpress seo:check --fix

What gets fixed:

  • Missing meta descriptions (generated from content)
  • Missing page titles (extracted from first heading)

What requires manual fix:

  • Broken links (need review)
  • Images without alt text (need descriptive text)
  • Titles/descriptions that are too long/short

---

Best Practices

1. Always Set Base URL

export default {
  sitemap: {
    baseUrl:'https://docs.example.com' 'https://docs.example.com'  // Required for SEO
  }
}

2. Write Descriptive Titles

Good:

---
title: API Authentication with OAuth 2.0
description: Learn how to authenticate API requests using OAuth 2.0 tokens
---

Bad:

---
title: Auth
description: Authentication
---

3. Optimize Images

  • Use alt text for all images
  • Compress images (use WebP or AVIF)
  • Include social card images (1200x630)
  • ![User authentication flow diagram showing OAuth 2.0 authorization](/images/auth-flow.png)

4. Structure Your Content

Use proper heading hierarchy:

# Main Title (H1) - One per page

## Major Section (H2)

### Subsection (H3)

#### Detail (H4)

5. Internal Linking

Link between related pages:

See also: [Configuration Guide](/config) and [CLI Reference](/cli)

6. Keep URLs Clean

Good:

  • /guide/getting-started
  • /api/authentication
  • /examples/deployment

Bad:

  • /page1
  • /doc-2024-10-29
  • /untitled

7. Regular SEO Audits

Run weekly:

bunpress seo:check && bunpress stats

8. Update Frequently

Set appropriate changefreq in sitemap:

changefreqMap: {'/changelog'
  '/changelog':'daily' 'daily',      // Frequently updated'/blog/*'
  '/blog/*':'weekly' 'weekly',        // Regular updates'/guide/*'
  '/guide/*':'monthly' 'monthly',      // Stable content'/archive/*'
  '/archive/*':'yearly' 'yearly'      // Historical content
}

---

SEO Checklist

Before deploying:

  • [ ] Set sitemap.baseUrl in config
  • [ ] All pages have unique titles (10-60 chars)
  • [ ] All pages have descriptions (50-160 chars)
  • [ ] Social card image created (1200x630)
  • [ ] All images have descriptive alt text
  • [ ] No broken internal links
  • [ ] Canonical URLs configured
  • [ ] robots.txt configured
  • [ ] Run bunpress seo:check passes
  • [ ] Sitemap submitted to search engines

Submit Sitemap

After deployment:

1. Google Search Console

  • Add property: https://docs.example.com
  • Submit sitemap: https://docs.example.com/sitemap.xml

2. Bing Webmaster Tools

  • Add site: https://docs.example.com
  • Submit sitemap: https://docs.example.com/sitemap.xml

---

Advanced Topics

Custom SEO Transformations

Modify sitemap entries before generation:

export default {
  sitemap: {
    transform: (entry) => {
      // Add custom metadata
      if (entry.url.includes('/api/''/api/')) {
        entry.priority = 0.9;
        entry.changefreq ='weekly' 'weekly';
      }

      // Exclude beta pages
      if (entry.url.includes('/beta/''/beta/')) {
        return null;
      }

      return entry;
    }
  }
}

Dynamic Meta Tags

Generate meta tags based on content:

// Custom plugin
export default {
  plugins: [
    {
      name:'dynamic-meta' 'dynamic-meta',
      extendConfig: (config) => {
        // Add custom meta tag logic
        return config;
      }
    }
  ]
}

Multi-Language SEO

Configure for multiple languages:

export default {
  sitemap: {
    baseUrl:'https://docs.example.com' 'https://docs.example.com',
    // Include language in URLs
  },
  markdown: {
    meta: {'og:locale'
      'og:'en_US'locale': 'en_US','og:locale:alternate'
      'og:locale:alternate': ['es_ES''es_ES','fr_FR' 'fr_FR']
    }
  }
}

---

Monitoring & Analytics

Google Search Console

Monitor:

  • Indexing status
  • Search performance
  • Mobile usability
  • Core Web Vitals

Analytics Integration

See Configuration Guide for privacy-focused analytics with Fathom.

---

---

Need Help?