RSS Feed Configuration
Stati supports automatic RSS feed generation for your content. RSS feeds allow visitors to subscribe to your content and receive updates in their feed readers.
Overview
RSS feed generation in Stati:
- Production-only: RSS feeds are only generated during production builds
- Auto-regenerate: Feeds regenerate on every production build with latest content
- Multiple feeds: Support for multiple feeds with different content
- Highly customizable: Field mappings, content filtering, and custom metadata
- Works out of the box: Minimal configuration required
Basic Configuration
Enable RSS feed generation in your stati.config.ts:
import { defineConfig } from '@stati/core';
export default defineConfig({
site: {
title: 'My Blog',
baseUrl: 'https://example.com',
},
rss: {
enabled: true,
feeds: [
{
filename: 'feed.xml',
title: 'My Blog Posts',
description: 'Latest articles from my blog',
},
],
},
});
This minimal configuration will generate a feed.xml file containing all your pages.
Content Filtering
Filter by Directory
Use contentPatterns to include only specific content:
rss: {
enabled: true,
feeds: [
{
filename: 'blog.xml',
title: 'Blog Feed',
description: 'Latest blog posts',
contentPatterns: ['blog/**'], // Only pages in blog directory
},
],
}
Exclude Patterns
Use excludePatterns to exclude specific content:
rss: {
enabled: true,
feeds: [
{
filename: 'feed.xml',
title: 'Main Feed',
description: 'All content except drafts',
excludePatterns: ['**/draft-*', '**/index.md'],
},
],
}
Custom Filter Function
For fine-grained control, use a custom filter function:
rss: {
enabled: true,
feeds: [
{
filename: 'featured.xml',
title: 'Featured Posts',
description: 'Hand-picked featured articles',
filter: (page) => page.frontMatter.featured === true,
},
],
}
Multiple Feeds
You can create multiple feeds targeting different content:
rss: {
enabled: true,
feeds: [
{
filename: 'feed.xml',
title: 'All Posts',
description: 'All blog posts and articles',
},
{
filename: 'blog.xml',
title: 'Blog Posts',
description: 'Latest blog posts',
contentPatterns: ['blog/**'],
maxItems: 20,
},
{
filename: 'news.xml',
title: 'News Feed',
description: 'Latest news updates',
contentPatterns: ['news/**'],
maxItems: 10,
},
],
}
Feed Metadata
Customize your feed with optional metadata:
{
filename: 'feed.xml',
title: 'My Blog',
description: 'Articles about web development',
// Optional metadata
language: 'en-US',
copyright: 'Copyright 2025 My Company',
category: 'Technology',
ttl: 60, // Cache for 60 minutes
// Managing editor
managingEditor: 'editor@example.com (Jane Doe)',
// Webmaster
webMaster: 'webmaster@example.com (John Smith)',
// Feed image
image: {
url: 'https://example.com/logo.png',
title: 'Site Logo',
link: 'https://example.com',
width: 144,
height: 144,
},
}
Sorting and Limiting
Sort Order
Control the order of items in your feed:
{
filename: 'feed.xml',
title: 'My Feed',
description: 'Latest posts',
sortBy: 'date-desc', // Options: 'date-desc', 'date-asc', 'title-asc', 'title-desc', 'custom'
}
Custom Sort Function
{
filename: 'feed.xml',
title: 'My Feed',
description: 'Latest posts',
sortBy: 'custom',
sortFn: (a, b) => {
// Custom sorting logic
const priorityA = a.frontMatter.priority || 0;
const priorityB = b.frontMatter.priority || 0;
return priorityB - priorityA; // Higher priority first
},
}
Limit Items
Limit the number of items in a feed:
{
filename: 'feed.xml',
title: 'Recent Posts',
description: 'Last 10 posts',
maxItems: 10,
}
Field Mapping
Customize how page data maps to RSS feed items:
Default Mapping
By default, Stati uses these frontmatter fields:
title→ RSS item titledescription→ RSS item descriptionpublishedAtordate→ RSS item pubDatetags→ RSS item categories
Custom Field Names
Map to different frontmatter fields:
{
filename: 'feed.xml',
title: 'My Feed',
description: 'Latest posts',
itemMapping: {
title: 'headline', // Use 'headline' instead of 'title'
description: 'excerpt', // Use 'excerpt' instead of 'description'
pubDate: 'publishDate', // Use 'publishDate' instead of 'publishedAt'
author: 'authorName', // Use 'authorName' instead of 'author'
category: 'categories', // Use 'categories' instead of 'tags'
},
}
Field Mapping Functions
Use functions for custom transformations:
{
filename: 'feed.xml',
title: 'My Feed',
description: 'Latest posts',
itemMapping: {
// Transform title
title: (page) => `${page.frontMatter.title} - My Blog`,
// Build custom description
description: (page) =>
page.frontMatter.excerpt || page.frontMatter.description || 'Read more...',
// Custom author format
author: (page) => {
const author = page.frontMatter.author;
const email = page.frontMatter.email;
return email ? `${email} (${author})` : undefined;
},
// Custom link
link: (page, config) =>
`${config.site.baseUrl}/posts${page.url}?utm_source=rss`,
},
}
Include Full Content
Include the full HTML content in feed items:
{
filename: 'feed.xml',
title: 'My Feed',
description: 'Latest posts with full content',
itemMapping: {
includeContent: true, // Include rendered HTML in description
},
}
Advanced Features
Custom Namespaces
Add custom XML namespaces for RSS extensions:
{
filename: 'feed.xml',
title: 'My Feed',
description: 'Latest posts',
namespaces: {
'content': 'http://purl.org/rss/1.0/modules/content/',
'dc': 'http://purl.org/dc/elements/1.1/',
},
}
Custom Item Elements
Add custom XML elements to each item:
{
filename: 'feed.xml',
title: 'My Feed',
description: 'Latest posts',
customItemElements: (page) => ({
'dc:creator': page.frontMatter.author,
'content:encoded': page.content,
'custom:readTime': `${page.frontMatter.readTime} min`,
}),
}
Enclosures (Media Files)
Add enclosures for podcasts or other media:
{
filename: 'podcast.xml',
title: 'My Podcast',
description: 'Latest podcast episodes',
enclosure: (page) => {
if (page.frontMatter.audioUrl) {
return {
url: page.frontMatter.audioUrl,
length: page.frontMatter.audioSize, // Size in bytes
type: 'audio/mpeg',
};
}
return undefined;
},
}
Real-World Examples
Blog Feed
rss: {
enabled: true,
feeds: [
{
filename: 'feed.xml',
title: 'My Development Blog',
description: 'Articles about web development, JavaScript, and more',
contentPatterns: ['blog/**'],
language: 'en-US',
copyright: 'Copyright 2025 Your Name',
category: 'Technology',
maxItems: 20,
sortBy: 'date-desc',
itemMapping: {
category: 'tags',
includeContent: false,
},
},
],
}
News Site with Multiple Feeds
rss: {
enabled: true,
feeds: [
{
filename: 'all.xml',
title: 'All News',
description: 'Complete news feed',
maxItems: 50,
},
{
filename: 'breaking.xml',
title: 'Breaking News',
description: 'Breaking news only',
filter: (page) => page.frontMatter.breaking === true,
maxItems: 10,
},
{
filename: 'sports.xml',
title: 'Sports News',
description: 'Sports coverage',
contentPatterns: ['news/sports/**'],
maxItems: 20,
},
],
}
Podcast Feed
rss: {
enabled: true,
feeds: [
{
filename: 'podcast.xml',
title: 'My Tech Podcast',
description: 'Weekly discussions about technology',
contentPatterns: ['episodes/**'],
language: 'en-US',
category: 'Technology',
image: {
url: 'https://example.com/podcast-cover.jpg',
title: 'My Tech Podcast',
link: 'https://example.com/podcast',
},
enclosure: (page) => ({
url: page.frontMatter.audioUrl,
length: page.frontMatter.audioSize,
type: 'audio/mpeg',
}),
itemMapping: {
author: (page) => `podcast@example.com (${page.frontMatter.host})`,
description: 'summary',
},
},
],
}
Configuration Validation
Stati automatically validates your RSS configuration during the build process. If there are any errors, the build will display them and continue without generating the problematic feeds.
Automatic Validation
Validation happens automatically when you run a production build:
export default defineConfig({
rss: {
enabled: true,
feeds: [
{
filename: 'feed.xml',
title: 'My Blog',
description: 'Latest posts',
// Validation will check:
// - Required fields are present
// - Email formats are valid
// - Image dimensions are within limits
// - No duplicate filenames
},
],
},
});
Manual Validation
You can also validate RSS configuration programmatically:
import { validateRSSConfig } from '@stati/core';
const result = validateRSSConfig(config.rss);
if (!result.valid) {
console.error('RSS configuration errors:');
result.errors.forEach(error => console.error(` - ${error}`));
}
if (result.warnings.length > 0) {
console.warn('RSS configuration warnings:');
result.warnings.forEach(warning => console.warn(` - ${warning}`));
}
Validation Rules
Errors (will prevent feed generation):
- Missing required fields (
filename,title,description) - Invalid TTL value (must be non-negative)
- Duplicate feed filenames
- Missing image fields when image is specified
Warnings (informational only):
- Email addresses not in correct format
- Image dimensions exceeding RSS 2.0 recommendations (144×400 max)
- Filename not ending in
.xml - TTL set to 0 (no caching)
- Empty content patterns array
For more details on validation, see the RSS API Reference.
Development vs Production
Important: RSS feeds are only generated in production builds, not in development mode.
# RSS feeds will NOT be generated
npm run dev
# RSS feeds WILL be generated
npm run build
This is by design to avoid unnecessary regeneration during development. When you run a production build, all enabled feeds will be regenerated with the latest content.
Troubleshooting
Feed Not Generated
If your feed isn’t being generated:
- Check environment: Ensure you’re running a production build (
npm run build, notnpm run dev) - Verify enabled: Ensure
rss.enabled: truein your config - Check feed config: Verify your feed has required fields (
filename,title,description) - Check validation errors: Look for validation errors in the build output
- Check content patterns: If using
contentPatterns, ensure they match your content
Empty Feed
If your feed is empty:
- Check content patterns: Verify patterns match your content paths
- Check exclude patterns: Ensure you’re not excluding all content
- Check filter function: Verify your custom filter isn’t too restrictive
- Check maxItems: Ensure
maxItemsisn’t set to 0
Invalid XML
If your feed has XML errors:
- Check special characters: Stati automatically escapes XML characters
- Check custom elements: Ensure custom elements use valid XML tag names
- Validate feed: Use an RSS validator to check your feed
Best Practices
- Use clear titles: Make feed titles descriptive and unique
- Provide good descriptions: Write clear descriptions for both feeds and items
- Limit items: Use
maxItemsto keep feeds manageable (10-50 items typical) - Sort by date: Most recent content first (
date-desc) is standard - Include categories: Use tags/categories to help readers filter content
- Set TTL: Use
ttlto suggest appropriate cache duration - Test feeds: Validate generated feeds with RSS validators
- Link in HTML: Add
<link>tags in your HTML to advertise feeds
Next Steps
- Learn about SEO configuration
- Configure Sitemap generation
- Explore Build hooks