RSS Generator

Introduction

The RSS generator (scripts/generate_rss.ts) produces per-language RSS 2.0 (feed.xml) and JSON Feed 1.1 (feed.json) files for the blog directory. It reads .md files only - no database or runtime dependency - so it works on statically generated sites. Per-post metadata is read from frontmatter, and the full post content is rendered to HTML for the feed.

bun rss

This should be run after bun ssg - it reads from the generated dist/ directory.

CLI Options

bun scripts/generate_rss.ts [options]
OptionDefaultDescription
--public <dir>./src/publicSource directory
--dist <dir>./distOutput directory
--site-url <url>$SITE_URL (required)Absolute origin for feed URLs
--blog-dir <name>$BLOG_DIR (required)Sub-directory under --public to scan for markdown posts
--formats <list>xml,jsonComma-separated list: xml, json, or both
--max-items <n>50Maximum items per feed
--feed-title <text>-Override the feed title (default: "<site_name> - <blog>")
--feed-description <text>-Override the feed description (default: per-language)
--help-Print usage and exit

If --site-url is not provided and SITE_URL is not in the environment, the script exits with an error.

Output

For each active language, the generator writes to the blog's output directory:

FileFormatDescription
dist/blog/feed.xmlRSS 2.0Default language RSS feed
dist/blog/feed.jsonJSON Feed 1.1Default language JSON feed
dist/en/blog/feed.xmlRSS 2.0English RSS feed
dist/en/blog/feed.jsonJSON Feed 1.1English JSON feed

The output path mirrors the per-language structure: default language at root, others under /{lang}/.

Per-Post Frontmatter

Each blog post (.md file) can configure its feed entry through frontmatter:

FieldTypeDefaultDescription
titlestringFirst # HeadingPost title for the feed entry
published_atdate stringFile mtimePublication date. Format: YYYY-MM-DD or full ISO datetime
datedate stringFile mtimeAlias for published_at
descriptionstringFirst paragraphPost summary for the feed. Falls back to the first paragraph
summarystringFirst paragraphAlias for description
abstractstringFirst paragraphAlias for description (academic layout)
authorstring or object-Single author: "Name" or {name: "Name", email: "..."}
authorsarray-Multiple authors: [{name: "A", email: "..."}, {name: "B"}]
rssbooleantrueSet to false to exclude this post from the feed
noindexbooleanfalseAlso excludes from the feed (shared with sitemap)

Author Resolution

The author resolution chain:

  1. authors array (first entry used for RSS <author>, all entries for JSON Feed)
  2. author (string or {name, email, url} object)
  3. No author - the <author> element is omitted

For the RSS <author> element, the format is email (Name):

<author>matic@reepolee.com (Matic Jurglic)</author>

Description Resolution

The description resolution chain:

  1. description frontmatter field
  2. summary frontmatter field (alias)
  3. abstract frontmatter field (alias)
  4. First paragraph of the markdown body (stripped of formatting)

Descriptions are truncated to 320 characters with an ellipsis.

Feed Formats

RSS 2.0

Each feed item includes:

ElementSource
<title>Post title
<link>Full URL to the post
<guid>Same as <link> (isPermaLink="true")
<pubDate>RFC 822 date
<description>Post description (truncated, CDATA-wrapped)
<content:encoded>Full post HTML (CDATA-wrapped)
<author>First author, if present

JSON Feed 1.1

Each feed item includes:

FieldSource
idFull URL to the post
urlFull URL to the post
titlePost title
summaryPost description
content_htmlFull post HTML
date_publishedISO 8601 date
authorsArray of {name, url} (if any authors are set)

How It Works

  1. Loads translations to build the route map for localized URLs
  2. Collects markdown files from the blog directory, excluding index files
  3. Resolves language variants for each post ({name}.{lang}.md{name}.md)
  4. Parses frontmatter for title, date, description, authors, and exclusion flags
  5. Renders markdown body to HTML using Bun.markdown.html() (same as the static generation script)
  6. Strips markdown from descriptions for plain-text feed content
  7. Sorts posts by date (newest first)
  8. Builds feeds for each active language in the requested formats