Skip to content
Blume
Esc
↑↓navigate↵open⌘Jpreview
On this page

Changelogs

Author release notes as ordinary content files or source them from GitHub Releases, and Blume builds a timeline page and an RSS feed automatically.

Blume ships a changelog out of the box. Write each release as a normal content file, mark it type: changelog, and Blume collects every entry into a generated index page and an RSS feed — no layout to build, no list to maintain. Or skip the files entirely and source your changelog from GitHub Releases.

Write an entry

A changelog entry is a regular .md or .mdx page with type: changelog in its frontmatter. By convention they live under changelog/, but the type — not the folder — is what matters:

---
title: v1.2.0
type: changelog
date: 2026-06-20
changelog:
  version: 1.2.0
  category: Features
---

A big batch of components landed this release — columns, frames, trees, and tooltips, plus code groups that render as proper language tabs.

- New `Accordion`, `Expandable`, and `Tooltip` components
- `CodeGroup` tabs with flush code blocks

Give every entry a date so the index and feed sort newest-first. An unquoted YAML date is fine — Blume normalizes it.

The changelog object

The optional changelog object adds richer metadata for the index and feed:

PropType
changelog.version?string

Release version. Falls back to a v-prefixed label when there's no title.

Typestring
changelog.category?string

Shown as a tag beside the entry, e.g. Release, Features, Fixes.

Typestring
changelog.date?string

Publish date. May live here or at the top level — both feed the index and RSS feed.

Typestring

The index page

Once you have at least one type: changelog entry, Blume generates a /changelog page automatically. It’s a focused, full-width index — no sidebar or table of contents — that lists every release as one row, newest-first and grouped by year, so a long history stays a short page (well under the size an agent can read in a single context window):

  • The entry title is the row’s label — or v{version} when there’s no title. It links to that entry’s own page, which is where the release notes render in full.
  • The category renders as a tag beside the title, so a reader can tell a release from a prerelease, or features from fixes, at a glance.
  • The date follows the configured dateFormat, minus the year the row’s group already shows.
  • Drafts and sidebar.hidden entries are skipped.

The page is headed Changelog (in English), with a one-line description below. Set your own with changelog in your config; they also become the page’s <title>, meta description, and OG card, and the top of its Markdown mirror at /changelog.md:

changelog: {
  title: "Release notes",
  description: "Every Acme SDK release, newest first.",
},

Each takes a map of locale code to text too, like a header tab label. The index renders in the default locale, so it shows that locale’s entry. Leave either unset and it keeps the built-in text, which a UI string override (changelog.title and changelog.description under i18n.ui) replaces.

The page appears only when nothing already occupies the /changelog route.

Writing your own index

To put something above the list — an introduction, a link to the feed, a note about your release cadence — write the page yourself and place <Changelog /> where the list belongs. Blume still owns the list, so you only write the parts it has no slot for:

---
title: Changelog
description: Every Acme SDK release, newest first.
mode: center
---

Every release, newest first. Subscribe to the [RSS feed](/changelog/rss.xml) to follow along.

<Changelog />

A content page at /changelog takes over the route, so the generated page steps aside and yours renders instead. Put it at changelog/index.mdx, beside your entries, so the sidebar’s Changelog group links to it — a changelog.mdx next to the folder adds a second Changelog item to the sidebar. mode: center gives it the generated page’s layout — no sidebar, no table of contents, a wider centered column — and the generated page renders the same component, so the two can’t drift apart. The list downlevels to Markdown on the agent surfaces (/changelog.md, llms-full.txt, MCP get_page, search) exactly as the generated page’s does.

The list is always the default locale’s entries, wherever the tag sits — the rule every surface that publishes it already follows, so a translated page lists the same releases rather than disagreeing about which exist. Its dates read in the page’s own language.

Replacing the page entirely

For a design the component can’t express, add a custom page at pages/changelog.astro — it takes over and Blume stops generating the default index. The <Update> component the previous timeline was built from still ships for a custom page that wants inline release notes. It isn’t one of the MDX components, so import it in the .astro page itself: import Update from "blume/components/content/Update.astro";.

Building the list yourself means reproducing what <Changelog /> does, including one thing that fails quietly: entries from a non-filesystem source (such as GitHub Releases) render through a parallel staged collection, so a page that reads getCollection("docs") alone lists none of them, with no warning. Prefer <Changelog /> in a content page unless you genuinely need different markup.

From GitHub Releases

Rather than authoring entries by hand, point the built-in githubReleases() source at a repo and every release becomes a type: changelog entry — the same timeline and feed, fed straight from the releases you already publish. Blume’s own changelog is built this way:

import { filesystem, githubReleases } from "blume/sources";

content: {
  sources: [
    filesystem({ root: "content" }),
    githubReleases({
      prefix: "changelog",
      owner: "acme",
      repo: "sdk",
    }),
  ],
}

The release name becomes the title, its tag becomes changelog.version, and its published date sorts the timeline. Each release page also gets a unique meta description summarized from its notes — markdown stripped, section headings and changeset commit-hash prefixes dropped, trimmed to the search-snippet length blume audit checks for — instead of falling back to the site description. A private repo authenticates with the GITHUB_TOKEN environment variable. See GitHub Releases for every option.

Keep entries out of the sidebar

Changelog entries are ordinary pages, so the generated sidebar lists them like any other: a changelog/ folder, or a githubReleases() source with prefix: "changelog", becomes a Changelog group, newest entry first, that grows with every release. Previous/next links run through it too, so the last docs page can lead into the newest release.

To keep the entries out of the docs sidebar, link the changelog with a header tab rather than a header action:

navigation: {
  tabs: [
    { label: "Docs", path: "/" },
    { label: "Changelog", path: "/changelog" },
  ],
}

The /changelog tab opens the index, with no href needed, and owns the changelog/ section: pages outside it stop listing the releases, and their previous/next links stay among the docs. An entry’s own page shows the release list as its sidebar. The index, the RSS feed, llms.txt, the sitemap, and search still list every entry. The tab’s path has to match the folder or prefix the entries live under. The Docs tab at / is optional; it gives readers a tab to return to.

Setting sidebar.hidden on the entries doesn’t do this: it unlists them everywhere, the index and the feed included.

The RSS feed

Blume also builds a changelog feed at /changelog/rss.xml, sorted newest-first by date. Feeds need an absolute site URL, so set deployment.site; Blume then injects a <link rel="alternate"> tag on every page so readers discover it automatically.

The feed is on by default. Tune it under seo.rss:

seo: {
  rss: {
    enabled: true,
    types: ["blog", "changelog"],
    limit: 50,
  },
}

Remove "changelog" from rss.types to skip the feed while keeping the timeline.

Structured data

When structured data is on, each changelog entry is emitted as a schema.org TechArticle with its description and publish date, so search engines can index releases as dated articles.

Last updated on

Was this page helpful?