---
title: Changelog
description: 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 timeline 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](#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:

```mdx changelog/v1-2-0.mdx lineNumbers
---
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 timeline 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 timeline and feed:

| Prop | Type | Default | Description |
| - | - | - | - |
| `changelog.version?` | `string` | - | Release version. Falls back to a v-prefixed label when there's no title. |
| `changelog.category?` | `string` | - | Shown as a tag beside the entry, e.g. Release, Features, Fixes. |
| `changelog.date?` | `string` | - | Publish date. May live here or at the top level — both feed the timeline and RSS feed. |

## The timeline page

Once you have at least one `type: changelog` entry, Blume generates a **`/changelog`** page automatically. It renders as a focused, full-width timeline — no sidebar or table of contents — with each entry newest-first, showing its date, label, and `category` tag in a left rail beside its content:

- The entry **title** becomes its label — or `v{version}` when there's no title. It links to that entry's own page, so a release is both a line in the timeline and a shareable permalink.
- The `category` renders as a tag next to the date.
- Drafts and `sidebar.hidden` entries are skipped.

The page appears only when nothing already occupies the `/changelog` route. To replace it with your own design, add a [custom page](/docs/advanced/custom-pages) at `pages/changelog.astro` — it takes over and Blume stops generating the default timeline.

Because this page is generated rather than authored, it isn't part of the content tree — so a header [tab](/docs/content/navigation#tabs) pointing at `/changelog` resolves to the newest entry instead. Give the tab an `href` to land on the index itself:

```ts blume.config.ts
navigation: {
  tabs: [
    { label: "Changelog", path: "/changelog", href: "/changelog" },
  ],
}
```

### Grouped by major version

When your versions follow [semver](https://semver.org) and span more than one major, Blume paginates the timeline by major version. Only the newest major line is shown, with a **Show N.x releases** button at the bottom that reveals the next-oldest major one click at a time:

- Detection is automatic — no configuration. It kicks in only when every listed release parses as `major.minor.patch` and there is more than one major; otherwise the timeline stays flat.
- It tolerates the scoped tags monorepos publish, so `pkg@2.0.0` groups under `2.x` and `pkg@1.4.0` under `1.x`.
- It's progressive enhancement: every release is still in the page's HTML (and its RSS feed and search index), so readers without JavaScript — and crawlers — see the complete history. The button only collapses older majors once the page hydrates.

## From GitHub Releases

Rather than authoring entries by hand, point the built-in [`github-releases` source](/docs/content/sources#github-releases) 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](/changelog) is built this way:

```ts blume.config.ts
content: {
  sources: [
    { type: "filesystem", root: "content" },
    {
      type: "github-releases",
      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`](/docs/reference/cli#auditing-the-built-site) checks for — instead of falling back to the site description. A private repo authenticates with the `GITHUB_TOKEN` environment variable. See [Content sources](/docs/content/sources#github-releases) for every option.

## 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`](/docs/deployment); 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`](/docs/configuration/seo#rss-feeds):

```ts blume.config.ts lineNumbers
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](/docs/configuration/seo#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.

<CardGroup cols={2}>
  <Card
    title="Frontmatter"
    href="/docs/reference/frontmatter#changelog"
    icon="file"
  >
    The full changelog frontmatter schema.
  </Card>
  <Card title="Custom Pages" href="/docs/advanced/custom-pages" icon="folder">
    Replace the generated timeline with your own layout.
  </Card>
</CardGroup>
