Feeds ¶
Feeds are the core differentiator of markata-go. A feed is a filtered, sorted, paginated collection of posts that can output to multiple formats simultaneously from a single definition.
Prerequisites: Before diving into feeds, you should understand:
- Frontmatter Guide - How post metadata works (feeds filter based on frontmatter)
- Configuration Guide - Basic config file structure
Why Feeds Matter ¶ #
Feeds solve a common problem in static site generation: you need the same collection of posts in different formats for different consumers.
FEED DEFINITION
filter: "published == True and 'python' in tags"
sort: "date"
reverse: true
items_per_page: 10
|
v
OUTPUT FORMATS
+-------+--------+-------+-------+-------+----------+------+---------+
| HTML | Simple | RSS | Atom | JSON | Markdown | Text | Sitemap |
| index | list | feed | feed | API | list | list | XML |
+-------+--------+-------+-------+-------+----------+------+---------+
Benefits:
- One definition, many outputs - Define a collection once, get HTML pages, a simple list view, RSS, Atom, JSON API, sitemap, etc.
- Composable - Feeds can share filters or inherit from defaults
- Flexible - Every “index page” is a feed: home, archives, tags, categories, search indexes
- Familiar - Mirrors how content platforms work (RSS readers, APIs, syndication)
Basic Feed Configuration ¶ #
A feed is defined in your markata-go.toml using the [[markata-go.feeds]] array:
[[markata-go.feeds]]
slug = "blog"
title = "Blog"
filter = "published == True"
sort = "date"
reverse = true
This creates a feed at /blog/ with:
- All published posts
- Sorted by date (newest first)
- HTML, simple HTML, RSS, Atom, JSON, and sitemap output (default formats)
Minimal Example ¶ #
[[markata-go.feeds]]
slug = "posts"
title = "All Posts"
filter = "published == True"
If you use the default config, markata-go already includes an archive feed at /archive/.
Full Configuration Example ¶ #
[[markata-go.feeds]]
# Identity
slug = "blog" # URL path: /blog/
title = "All Posts" # Display title
description = "Latest blog posts" # Meta description
# Content Selection
filter = "published == True and date <= today"
sort = "date"
reverse = true # Newest first
include_private = false # Include private posts (default: false)
# Pagination
items_per_page = 10 # 0 = no pagination (all on one page)
orphan_threshold = 3 # If last page has <=3 items, merge with previous
# Output Formats
[markata-go.feeds.formats]
html = true # /blog/index.html, /blog/page/2/index.html
simple_html = true # /blog/simple/index.html
rss = true # /blog/rss.xml
atom = true # /blog/atom.xml
json = true # /blog/feed.json
sitemap = true # /blog/sitemap.xml
markdown = false # /blog.md
text = false # /blog.txt
# Custom Templates
[markata-go.feeds.templates]
html = "feed.html" # Template for HTML pages
card = "partials/card.html" # Template for post cards in list
rss = "rss.xml" # Template for RSS
atom = "atom.xml" # Template for Atom
json = "feed.json" # Template for JSON
Filtering Posts ¶ #
The filter field uses a Python-like expression syntax to select which posts appear in a feed.
Filter Operators ¶ #
| Operator | Description | Example |
|---|---|---|
== |
Equal | published == True |
!= |
Not equal | draft != True |
>, >= |
Greater than | date >= '2024-01-01' |
<, <= |
Less than | date < '2025-01-01' |
in |
Contains (tags) | 'python' in tags |
contains |
String contains | tags contains 'python' |
and |
Logical AND | published == True and featured == True |
or |
Logical OR | 'python' in tags or 'go' in tags |
not |
Logical NOT | not draft |
Filter Examples ¶ #
# Published posts only
filter = "published == True"
# Exclude drafts
filter = "draft == False"
# Posts with a specific tag
filter = "'tutorial' in tags"
# Multiple tags (OR)
filter = "'python' in tags or 'go' in tags"
# Combined conditions
filter = "published == True and featured == True"
# Date range
filter = "date >= '2024-01-01' and date < '2025-01-01'"
# By slug
filter = "slug != 'about'"
# Complex filter
filter = "published == True and ('python' in tags or 'go' in tags) and featured == True"
Sorting Posts ¶ #
Control the order of posts with sort and reverse:
[[markata-go.feeds]]
slug = "blog"
sort = "date" # Field to sort by
reverse = true # true = descending (newest first)
Sort Fields ¶ #
You can sort by any post field:
| Field | Description |
|---|---|
date |
Publication date (most common) |
title |
Alphabetical by title |
slug |
Alphabetical by slug |
reading_time |
By reading time |
| Any frontmatter | Sort by custom fields |
Sort Examples ¶ #
# Newest first (most common)
sort = "date"
reverse = true
# Oldest first (chronological)
sort = "date"
reverse = false
# Alphabetical by title
sort = "title"
reverse = false
# Custom field (priority)
sort = "priority"
reverse = true
Pagination ¶ #
Feeds support three pagination strategies for different use cases.
Pagination Configuration ¶ #
[[markata-go.feeds]]
slug = "blog"
items_per_page = 10 # Posts per page (0 = all on one page)
orphan_threshold = 3 # Merge last page if <= N items
pagination_type = "manual" # Pagination strategy
Feed Timestamps ¶ #
Feed timestamps are deterministic and based on content, not build time:
- Atom
<updated>and RSS<lastBuildDate>use the most recent post date in the feed. - If no posts have dates, these fields are omitted.
This avoids no-change incremental builds rewriting feeds.
Pagination Types ¶ #
| Type | Description | Use Case |
|---|---|---|
manual |
Traditional page links | SEO-friendly, works without JavaScript |
htmx |
AJAX-based loading via HTMX | Modern, seamless UX without full page reloads |
js |
Custom JavaScript pagination | Full control over pagination behavior |
Manual Pagination (Default) ¶ #
Standard pagination with full page reloads:
[[markata-go.feeds]]
slug = "blog"
items_per_page = 10
pagination_type = "manual"
Generates:
/blog/index.html # Page 1
/blog/page/2/index.html # Page 2
/blog/page/3/index.html # Page 3
HTMX Pagination ¶ #
HTMX pagination provides seamless content loading without full page reloads:
[markata-go]
htmx_version = "2.0.8" # HTMX version to use
[[markata-go.feeds]]
slug = "blog"
items_per_page = 10
pagination_type = "htmx"
template = "feed.html"
partial_template = "feed_partial.html"
How it works:
- User clicks “Next” or page number
- HTMX intercepts click, sends GET request
- Server returns partial HTML (just the posts list)
- HTMX swaps new content into existing container
- URL updates via pushState (browser history works)
Output structure:
/blog/
index.html # Full page (page 1)
partial/
index.html # Partial content (page 1)
page/
2/
index.html # Full page (page 2)
partial/
index.html # Partial content (page 2)
HTMX template example:
<!-- feed.html (full page) -->
<div id="feed-content" hx-swap-oob="true">
{% include "feed_partial.html" %}
</div>
<nav class="pagination">
{% if pagination.has_prev %}
<a href="{{ feed.slug }}/page/{{ pagination.prev_page }}/"
hx-get="{{ feed.slug }}/page/{{ pagination.prev_page }}/partial/"
hx-target="#feed-content"
hx-push-url="true">
Previous
</a>
{% endif %}
{% if pagination.has_next %}
<a href="{{ feed.slug }}/page/{{ pagination.next_page }}/"
hx-get="{{ feed.slug }}/page/{{ pagination.next_page }}/partial/"
hx-target="#feed-content"
hx-push-url="true">
Next
</a>
{% endif %}
</nav>
JavaScript Pagination ¶ #
For custom JavaScript implementations:
[[markata-go.feeds]]
slug = "blog"
items_per_page = 10
pagination_type = "js"
Generates a configuration file at /static/js/pagination-config.js:
window.paginationData = {
"enabled": true,
"type": "js",
"page": 1,
"totalPages": 5,
"totalPosts": 47,
"itemsShown": 10,
"feedName": "blog",
"hasNext": true
};
Orphan Threshold ¶ #
The orphan_threshold prevents tiny last pages:
[[markata-go.feeds]]
slug = "blog"
items_per_page = 10
orphan_threshold = 3 # If last page has <=3 items, merge with previous
With 23 posts and items_per_page = 10:
- Without threshold: Page 1 (10), Page 2 (10), Page 3 (3)
- With threshold: Page 1 (10), Page 2 (13)
Output Formats ¶ #
Each feed can generate multiple output formats simultaneously.
HTML ¶ #
Paginated HTML index pages.
[markata-go.feeds.formats]
html = true
Output:
/blog/index.html # Page 1
/blog/page/2/index.html # Page 2
Simple HTML ¶ #
A compact, dense list view of posts designed to fit many entries on screen. Each post renders as a single line with title (as a link), date, and reading time. The simple feed is generated alongside the standard HTML feed automatically.
[markata-go.feeds.formats]
simple_html = true
Output:
/blog/simple/index.html # Page 1
/blog/simple/page/2/index.html # Page 2
The simple feed page includes a navigation switcher to toggle between the full (rich card) view and the simple list view. Each entry uses microformats2 markup (h-entry, p-name, dt-published).
When to use the simple format:
- Dense archives – Show many posts at a glance without scrolling through large cards
- Quick scanning – Readers who know what they’re looking for can scan titles and dates rapidly
- Low-bandwidth – Minimal HTML and no images, loads fast on slow connections
- Print-friendly – Styled for clean printing via
@media print
Disabling the simple format for a specific feed:
[[markata-go.feeds]]
slug = "api/posts"
formats = { simple_html = false }
RSS 2.0 ¶ #
RSS feed for feed readers.
[markata-go.feeds.formats]
rss = true
Output: /blog/rss.xml
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Blog</title>
<link>https://example.com/blog/</link>
<description>Latest blog posts</description>
<lastBuildDate>Mon, 15 Jan 2024 12:00:00 +0000</lastBuildDate>
<atom:link href="https://example.com/blog/rss.xml" rel="self" type="application/rss+xml"/>
<item>
<title>My Post</title>
<link>https://example.com/my-post/</link>
<guid isPermaLink="true">https://example.com/my-post/</guid>
<pubDate>Mon, 15 Jan 2024 12:00:00 +0000</pubDate>
<description>Post description...</description>
</item>
</channel>
</rss>
Atom ¶ #
Atom feed (RFC 4287).
[markata-go.feeds.formats]
atom = true
Output: /blog/atom.xml
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Blog</title>
<link href="https://example.com/blog/" rel="alternate"/>
<link href="https://example.com/blog/atom.xml" rel="self"/>
<id>https://example.com/blog/</id>
<updated>2024-01-15T12:00:00Z</updated>
<entry>
<title>My Post</title>
<link href="https://example.com/my-post/" rel="alternate"/>
<id>https://example.com/my-post/</id>
<published>2024-01-15T12:00:00Z</published>
<updated>2024-01-15T12:00:00Z</updated>
<summary>Post description...</summary>
</entry>
</feed>
JSON Feed ¶ #
JSON Feed (version 1.1) for modern feed readers and APIs.
[markata-go.feeds.formats]
json = true
Output: /blog/feed.json
{
"version": "https://jsonfeed.org/version/1.1",
"title": "Blog",
"home_page_url": "https://example.com",
"feed_url": "https://example.com/blog/feed.json",
"description": "Latest blog posts",
"items": [
{
"id": "https://example.com/my-post/",
"url": "https://example.com/my-post/",
"title": "My Post",
"content_html": "<p>Post content...</p>",
"summary": "Post description...",
"date_published": "2024-01-15T12:00:00Z",
"tags": ["go", "tutorial"]
}
]
}
Markdown ¶ #
Markdown list of posts (useful for READMEs, documentation).
[markata-go.feeds.formats]
markdown = true
Output: /blog.md
# Blog
Latest blog posts
- [My Post](/my-post/) - 2024-01-15
- [Another Post](/another-post/) - 2024-01-10
Plain Text ¶ #
Simple text list (useful for APIs, scripts, minimal readers).
[markata-go.feeds.formats]
text = true
Output: /blog.txt
Blog
====
Latest blog posts
2024-01-15 - My Post
/my-post/
2024-01-10 - Another Post
/another-post/
Text output always produces clean plain text – HTML entities are decoded to their literal characters and no HTML tags appear in the output. Links from HTML content are converted to footnote-style references. See the Templates Guide for details on using the plaintext filter.
Sitemap ¶ #
XML sitemap for search engines.
[markata-go.feeds.formats]
sitemap = true
Output: /blog/sitemap.xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/my-post/</loc>
<lastmod>2024-01-15</lastmod>
<changefreq>weekly</changefreq>
<priority>0.5</priority>
</url>
</urlset>
Auto-Generated Tag Feeds ¶ #
markata-go can automatically create feeds for each unique tag in your posts.
Enable Auto Tags ¶ #
[markata-go.feeds.auto_tags]
enabled = true
slug_prefix = "tags" # /tags/python/, /tags/go/
[markata-go.feeds.auto_tags.formats]
html = true
rss = true
Generated Output ¶ #
If your posts have tags python, go, and tutorial:
/tags/
python/
index.html
rss.xml
go/
index.html
rss.xml
tutorial/
index.html
rss.xml
Auto Categories ¶ #
Similar to tags, but for the category frontmatter field:
[markata-go.feeds.auto_categories]
enabled = true
slug_prefix = "categories"
[markata-go.feeds.auto_categories.formats]
html = true
rss = true
Auto Archives ¶ #
Automatic date-based archive feeds:
[markata-go.feeds.auto_archives]
enabled = true
slug_prefix = "archive"
yearly_feeds = true # /archive/2024/
monthly_feeds = true # /archive/2024/01/
[markata-go.feeds.auto_archives.formats]
html = true
Feed Defaults and Inheritance ¶ #
Configure defaults that apply to all feeds, then override as needed.
Global Defaults ¶ #
# Default values for ALL feeds
[markata-go.feeds.defaults]
items_per_page = 10
orphan_threshold = 3
[markata-go.feeds.defaults.formats]
html = true
rss = true
atom = false
json = false
markdown = false
text = false
[markata-go.feeds.defaults.templates]
html = "feed.html"
card = "partials/card.html"
rss = "rss.xml"
atom = "atom.xml"
json = "feed.json"
# Syndication settings (RSS/Atom/JSON limits)
[markata-go.feeds.syndication]
max_items = 20 # Max items in RSS/Atom feeds
include_content = false # Include full content or just summary
Inheritance Example ¶ #
# Global defaults
[markata-go.feeds.defaults]
items_per_page = 10
[markata-go.feeds.defaults.formats]
html = true
rss = true
atom = false
json = false
# Home page - override items_per_page and formats
[[markata-go.feeds]]
slug = ""
title = "Home"
filter = "published == True"
items_per_page = 5 # Override: fewer items
formats = { rss = false } # Override: no RSS for home
# Blog - inherits all defaults
[[markata-go.feeds]]
slug = "blog"
title = "Blog"
filter = "published == True"
# Inherits: items_per_page=10, html=true, rss=true
# API endpoint - completely different formats
[[markata-go.feeds]]
slug = "api/posts"
title = "Posts API"
filter = "published == True"
items_per_page = 0 # Override: no pagination
formats = { html = false, rss = false, json = true } # Override: JSON only
Format Override Behavior ¶ #
When overriding formats:
# Defaults: html=true, rss=true, atom=false, json=false
# Add to defaults (merge)
formats = { atom = true }
# Result: html=true, rss=true, atom=true, json=false
# Disable specific format
formats = { rss = false }
# Result: html=true, rss=false, atom=false, json=false
# Complete replacement
formats = { html = false, rss = false, atom = false, json = true }
# Result: json only
Common Patterns ¶ #
Home Page Feed ¶ #
The home page is a feed with an empty slug:
[[markata-go.feeds]]
slug = "" # Outputs to /index.html
title = "Recent Posts"
filter = "published == True"
sort = "date"
reverse = true
items_per_page = 5
[markata-go.feeds.formats]
html = true
rss = false # Usually no RSS on home page
Archive (All Posts, No Pagination) ¶ #
[[markata-go.feeds]]
slug = "archive"
title = "All Posts"
filter = "published == True"
sort = "date"
reverse = true
items_per_page = 0 # No pagination - all posts on one page
[markata-go.feeds.formats]
html = true
rss = false
Private Archive (Including Private Posts) ¶ #
If you want a feed that includes private posts (useful for personal archives or admin pages):
[[markata-go.feeds]]
slug = "private-archive"
title = "Private Archive"
filter = "published == True"
sort = "date"
reverse = true
include_private = true # Include private posts in this feed
[markata-go.feeds.formats]
html = true
rss = false # Usually don't syndicate private posts
Tag Pages (Manual) ¶ #
If you don’t want auto-generated tag feeds:
[[markata-go.feeds]]
slug = "tags/python"
title = "Python Posts"
filter = "published == True and 'python' in tags"
sort = "date"
reverse = true
Featured Posts ¶ #
[[markata-go.feeds]]
slug = "featured"
title = "Featured"
description = "Hand-picked articles"
filter = "published == True and featured == True"
sort = "date"
reverse = true
items_per_page = 6
JSON API Endpoint ¶ #
[[markata-go.feeds]]
slug = "api/posts"
title = "Posts API"
filter = "published == True"
sort = "date"
reverse = true
items_per_page = 0 # All posts
[markata-go.feeds.formats]
html = false
rss = false
json = true # JSON only
Search Index ¶ #
Generate a JSON index for client-side search:
[[markata-go.feeds]]
slug = "search"
title = "Search Index"
filter = "published == True"
[markata-go.feeds.formats]
json = true
[markata-go.feeds.templates]
json = "search-index.json"
Custom template (templates/search-index.json):
{
"posts": [
{% for post in feed.posts %}
{
"title": {{ post.title | tojson }},
"href": {{ post.href | tojson }},
"content": {{ post.content | striptags | truncate:500 | tojson }},
"tags": {{ post.tags | tojson }}
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}
Global Sitemap ¶ #
Root sitemap with all posts:
[[markata-go.feeds]]
slug = "" # Root
title = "Sitemap"
filter = "published == True"
sort = "date"
reverse = true
[markata-go.feeds.formats]
html = false # No HTML
sitemap = true # Sitemap only
Outputs /sitemap.xml at the root.
Tutorials Section ¶ #
[[markata-go.feeds]]
slug = "tutorials"
title = "Tutorials"
description = "Step-by-step guides"
filter = "published == True and 'tutorial' in tags"
sort = "date"
reverse = true
items_per_page = 10
[markata-go.feeds.formats]
html = true
rss = true
atom = true
json = true
Template Variables ¶ #
When rendering feed templates, these variables are available:
Feed Context (feed) ¶ #
| Variable | Type | Description |
|---|---|---|
feed.slug |
string | URL-safe identifier |
feed.title |
string | Display title |
feed.description |
string | Feed description |
feed.href |
string | Base URL path (/blog/) |
feed.posts |
[]Post | All matching posts (pre-pagination) |
Pagination Context (pagination) ¶ #
| Variable | Type | Description |
|---|---|---|
pagination.current_page |
int | Current page number (1-indexed) |
pagination.total_pages |
int | Total number of pages |
pagination.total_items |
int | Total posts in feed |
pagination.items_per_page |
int | Posts per page |
pagination.has_prev |
bool | Has previous page |
pagination.has_next |
bool | Has next page |
pagination.prev_url |
string | URL to previous page |
pagination.next_url |
string | URL to next page |
pagination.prev_page |
int | Previous page number |
pagination.next_page |
int | Next page number |
pagination.page_urls |
[]string | URLs for all pages |
Page Context (page) ¶ #
| Variable | Type | Description |
|---|---|---|
page.number |
int | Page number |
page.posts |
[]Post | Posts on this page |
page.has_prev |
bool | Has previous page |
page.has_next |
bool | Has next page |
page.prev_url |
string | Previous page URL |
page.next_url |
string | Next page URL |
Post Fields ¶ #
Each post in feed.posts or page.posts has:
| Field | Type | Description |
|---|---|---|
post.Title |
string | Post title |
post.Slug |
string | URL slug |
post.Href |
string | Relative URL (/my-post/) |
post.Date |
time | Publication date |
post.Published |
bool | Whether published |
post.Tags |
[]string | List of tags |
post.Description |
string | Post description |
post.Content |
string | Raw markdown |
post.ArticleHTML |
string | Rendered HTML |
post.Extra |
map | Additional frontmatter |
Template Example ¶ #
{% extends "base.html" %}
{% block content %}
<main>
<h1>{{ feed.title }}</h1>
{% if feed.description %}
<p class="description">{{ feed.description }}</p>
{% endif %}
<ul class="posts">
{% for post in page.posts %}
<li class="post">
<a href="{{ post.Href }}">
<h2>{{ post.Title }}</h2>
</a>
<time datetime="{{ post.Date|atom_date }}">
{{ post.Date|date_format:"January 2, 2006" }}
</time>
{% if post.Description %}
<p>{{ post.Description }}</p>
{% endif %}
</li>
{% endfor %}
</ul>
<nav class="pagination">
{% if page.has_prev %}
<a href="{{ page.prev_url }}" rel="prev">Previous</a>
{% endif %}
<span>Page {{ pagination.current_page }} of {{ pagination.total_pages }}</span>
{% if page.has_next %}
<a href="{{ page.next_url }}" rel="next">Next</a>
{% endif %}
</nav>
</main>
{% endblock %}
Template Filters for Feeds ¶ #
| Filter | Description | Example |
|---|---|---|
rss_date |
Format as RSS date | {{ date|rss_date }} |
atom_date |
Format as Atom/ISO date | {{ date|atom_date }} |
date_format |
Custom date format | {{ date|date_format:"2006-01-02" }} |
tojson |
Convert to JSON | {{ tags|tojson }} |
absolute_url |
Add base URL | {{ href|absolute_url:config.URL }} |
striptags |
Remove HTML tags | {{ html|striptags }} |
truncate |
Truncate to length | {{ text|truncate:100 }} |
Feed Discovery ¶ #
markata-go provides automatic feed discovery so visitors and feed readers can find the right feed for each page.
How It Works ¶ #
Every page automatically includes <link rel="alternate"> tags in the <head> for feed discovery. The feed advertised depends on the page:
- Posts with a sidebar feed - If a post participates in a feed sidebar (e.g., a series or guide), the discovery links point to that feed.
- Other pages - All other pages advertise the site’s default subscription feeds (
/rss.xml,/atom.xml).
This ensures readers always discover the most relevant feed for the content they’re viewing.
Template Context ¶ #
When rendering pages, markata-go injects a discovery_feed variable into the template context:
| Field | Type | Description |
|---|---|---|
discovery_feed.title |
string | Feed title |
discovery_feed.has_rss |
bool | RSS format available |
discovery_feed.has_atom |
bool | Atom format available |
discovery_feed.has_json |
bool | JSON format available |
discovery_feed.rss_url |
string | RSS feed URL |
discovery_feed.atom_url |
string | Atom feed URL |
discovery_feed.json_url |
string | JSON feed URL |
Default Template Behavior ¶ #
The default base.html template handles discovery automatically:
<head>
{% if config.head.alternate_feeds %}
{# Explicit override - user-configured feeds take precedence #}
{% for feed in config.head.alternate_feeds %}
<link rel="alternate" type="{{ feed.type }}" title="{{ feed.title }}" href="{{ feed.href }}">
{% endfor %}
{% elif discovery_feed %}
{# Automatic per-page discovery #}
{% if discovery_feed.has_rss %}
<link rel="alternate" type="application/rss+xml"
title="{{ discovery_feed.title }} (RSS)"
href="{{ discovery_feed.rss_url }}">
{% endif %}
{% if discovery_feed.has_atom %}
<link rel="alternate" type="application/atom+xml"
title="{{ discovery_feed.title }} (Atom)"
href="{{ discovery_feed.atom_url }}">
{% endif %}
{% if discovery_feed.has_json %}
<link rel="alternate" type="application/feed+json"
title="{{ discovery_feed.title }} (JSON)"
href="{{ discovery_feed.json_url }}">
{% endif %}
{% else %}
{# Fallback #}
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/rss.xml">
{% endif %}
</head>
Override with head.alternate_feeds ¶ #
If you need full control over discovery links, configure head.alternate_feeds explicitly:
[[markata-go.head.alternate_feeds]]
type = "application/rss+xml"
title = "My Custom Feed"
href = "/custom/rss.xml"
When head.alternate_feeds is set, it completely overrides the automatic discovery behavior.
Built-in Subscription Feeds ¶ #
markata-go automatically creates site-wide subscription feeds so visitors always have a way to subscribe.
Generated Feeds ¶ #
By default, these feeds are created automatically:
| Path | Description |
|---|---|
/rss.xml |
Site RSS feed (all published posts) |
/atom.xml |
Site Atom feed (all published posts) |
/archive/rss.xml |
Archive RSS feed (same content as root) |
/archive/atom.xml |
Archive Atom feed (same content as root) |
How It Works ¶ #
The subscription_feeds plugin creates two internal feeds:
- Root feed (
slug = "") - Generates/rss.xmland/atom.xml(no HTML to avoid overwriting your home page) - Archive feed (
slug = "archive") - Generates/archive/rss.xmland/archive/atom.xml
Both feeds contain the same items: all published posts sorted by date (newest first).
Customizing Subscription Feeds ¶ #
The built-in feeds use sensible defaults, but you can override them by defining your own feeds with the same slugs:
# Override the root subscription feed
[[markata-go.feeds]]
slug = ""
title = "My Site"
filter = "published == True and featured == True" # Only featured posts
sort = "date"
reverse = true
[markata-go.feeds.formats]
html = false # Still no HTML (don't overwrite home page)
rss = true
atom = true
Why Both Root and Archive? ¶ #
- Root feeds (
/rss.xml,/atom.xml) - The standard location feed readers check first - Archive feeds (
/archive/...) - Alternative paths for services that expect feeds in subdirectories
Both contain identical content, ensuring maximum compatibility with feed readers and syndication services.
Manual Feed Discovery Links ¶ #
If you need to add discovery links manually in a custom template:
<head>
<!-- RSS Feed -->
<link rel="alternate" type="application/rss+xml"
title="{{ feed.title }} (RSS)"
href="{{ feed.href }}rss.xml">
<!-- Atom Feed -->
<link rel="alternate" type="application/atom+xml"
title="{{ feed.title }} (Atom)"
href="{{ feed.href }}atom.xml">
<!-- JSON Feed -->
<link rel="alternate" type="application/feed+json"
title="{{ feed.title }} (JSON)"
href="{{ feed.href }}feed.json">
</head>
WebSub Discovery ¶ #
If you enable WebSub, markata-go also emits hub discovery links:
<head>
<link rel="hub" href="https://hub.example.com/">
</head>
RSS/Atom feeds include rel="hub" and rel="self" links when WebSub is enabled.
Configuration Reference ¶ #
Feed Config Fields ¶ #
| Field | Type | Default | Description |
|---|---|---|---|
slug |
string | Required | URL path ("" for root) |
title |
string | Required | Display title |
description |
string | "" |
Feed description |
filter |
string | "" |
Filter expression |
sort |
string | "date" |
Sort field |
reverse |
bool | true |
Sort direction (true=descending) |
include_private |
bool | false |
Include private posts in feed |
items_per_page |
int | 10 |
Posts per page (0=no pagination) |
orphan_threshold |
int | 3 |
Min items for separate page |
pagination_type |
string | "manual" |
manual, htmx, or js |
formats |
object | - | Output formats |
templates |
object | - | Custom templates |
Feed Formats ¶ #
| Field | Type | Default | Description |
|---|---|---|---|
html |
bool | true |
Generate HTML pages |
simple_html |
bool | true |
Generate simple list HTML pages |
rss |
bool | true |
Generate RSS feed |
atom |
bool | false |
Generate Atom feed |
json |
bool | false |
Generate JSON feed |
markdown |
bool | false |
Generate Markdown file |
text |
bool | false |
Generate text file |
sitemap |
bool | false |
Generate sitemap |
Feed Templates ¶ #
| Field | Type | Default | Description |
|---|---|---|---|
html |
string | "feed.html" |
HTML template |
simple_html |
string | "simple-feed.html" |
Simple list HTML template |
card |
string | "card.html" |
Post card template |
rss |
string | "feed.xml" |
RSS template |
atom |
string | "atom.xml" |
Atom template |
json |
string | "feed.json" |
JSON template |
Feed Defaults ¶ #
| Field | Type | Default | Description |
|---|---|---|---|
items_per_page |
int | 10 |
Default posts per page |
orphan_threshold |
int | 3 |
Default orphan threshold |
formats |
object | - | Default formats |
templates |
object | - | Default templates |
Syndication Settings ¶ #
| Field | Type | Default | Description |
|---|---|---|---|
max_items |
int | 20 |
Max items in RSS/Atom |
include_content |
bool | false |
Include full content |
Auto Tags Config ¶ #
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false |
Enable auto tag feeds |
slug_prefix |
string | "tags" |
URL prefix |
formats |
object | - | Output formats |
Auto Archives Config ¶ #
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false |
Enable auto archives |
slug_prefix |
string | "archive" |
URL prefix |
yearly_feeds |
bool | true |
Generate yearly feeds |
monthly_feeds |
bool | false |
Generate monthly feeds |
formats |
object | - | Output formats |
Complete Example ¶ #
[markata-go]
title = "My Blog"
url = "https://myblog.com"
author = "Jane Doe"
# =============================================================================
# FEED DEFAULTS
# =============================================================================
[markata-go.feeds.defaults]
items_per_page = 10
orphan_threshold = 3
[markata-go.feeds.defaults.formats]
html = true
rss = true
atom = true
json = false
[markata-go.feeds.defaults.templates]
html = "feed.html"
card = "partials/card.html"
[markata-go.feeds.syndication]
max_items = 20
include_content = false
# =============================================================================
# INDIVIDUAL FEEDS
# =============================================================================
# Home page
[[markata-go.feeds]]
slug = ""
title = "Recent Posts"
filter = "published == True"
sort = "date"
reverse = true
items_per_page = 5
formats = { rss = false, atom = false }
# Main blog feed
[[markata-go.feeds]]
slug = "blog"
title = "Blog"
description = "All blog posts"
filter = "published == True"
sort = "date"
reverse = true
# Tutorials
[[markata-go.feeds]]
slug = "tutorials"
title = "Tutorials"
filter = "published == True and 'tutorial' in tags"
sort = "date"
reverse = true
# Archive (no pagination)
[[markata-go.feeds]]
slug = "archive"
title = "Archive"
filter = "published == True"
sort = "date"
reverse = true
items_per_page = 0
formats = { rss = false, atom = false }
# JSON API
[[markata-go.feeds]]
slug = "api/posts"
title = "Posts API"
filter = "published == True"
sort = "date"
reverse = true
items_per_page = 0
formats = { html = false, rss = false, atom = false, json = true }
# =============================================================================
# AUTO-GENERATED FEEDS
# =============================================================================
[markata-go.feeds.auto_tags]
enabled = true
slug_prefix = "tags"
[markata-go.feeds.auto_tags.formats]
html = true
rss = true
Generated output:
public/
index.html # Home (5 posts)
blog/
index.html # Blog page 1
page/2/index.html # Blog page 2
simple/
index.html # Simple list page 1
page/2/index.html # Simple list page 2
rss.xml
atom.xml
tutorials/
index.html
simple/
index.html
rss.xml
atom.xml
archive/
index.html # All posts, no pagination
simple/
index.html
api/
posts/
feed.json # JSON API
tags/
python/
index.html
rss.xml
go/
index.html
rss.xml
Next Steps ¶ #
Now that you understand feeds, here are recommended next steps:
Customize feed appearance:
- Templates Guide - Customize how feeds and cards are rendered
Add syndication and discovery:
- Syndication Guide - Share your feeds on Mastodon, Twitter, and other platforms
Deploy your site:
- Deployment Guide - Deploy to production with CI/CD
See Also ¶ #
- Configuration Guide - Full configuration reference
- Templates Guide - Template system documentation
- Frontmatter Guide - Post metadata for filtering
- Quick Reference - Filter expression cheat sheet