Adding RSS Feeds to a Next.js Static Blog
A step-by-step guide on how to add RSS, Atom, and JSON feeds to a Next.js static blog using the Feed package

This blog now supports RSS feeds! Here's how we implemented it using the feed
package with Next.js static export and Velite for content management.
Dependencies
First, we added the required dependencies to our web app:
yarn workspace web add feed esbuild-register
RSS Generator
We created an RSS generator script that uses Velite's blog data to generate the feeds:
import { Feed } from "feed";
import fs from "fs";
import path from "path";
import { blogs } from "./.velite";
async function generateRssFeed() {
const site_url = process.env.NEXT_PUBLIC_SITE_URL || "https://subaud.io";
const feed = new Feed({
title: "Court Schuett's Blog",
description: "Technical blog posts about AWS, CDK, and web development",
id: site_url,
link: site_url,
language: "en",
favicon: `${site_url}/favicon.ico`,
copyright: `All rights reserved ${new Date().getFullYear()}`,
author: {
name: "Court Schuett",
link: site_url,
},
});
blogs
.filter((post) => post.published)
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
.forEach((post) => {
feed.addItem({
title: post.title,
id: `${site_url}/blog/${post.slugAsParams}`,
link: `${site_url}/blog/${post.slugAsParams}`,
description: post.description,
content: post.description,
author: [
{
name: "Court Schuett",
link: site_url,
},
],
date: new Date(post.date),
category: post.categories?.map((cat) => ({ name: cat })),
});
});
// Write to both public and out directories
const directories = [
path.join(process.cwd(), "public"),
path.join(process.cwd(), "out"),
];
for (const dir of directories) {
// Create directory if it doesn't exist
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// Write feed files
fs.writeFileSync(path.join(dir, "rss.xml"), feed.rss2());
fs.writeFileSync(path.join(dir, "feed.json"), feed.json1());
fs.writeFileSync(path.join(dir, "atom.xml"), feed.atom1());
}
}
generateRssFeed();
Build Process
We updated our build script in package.json
to generate the RSS feeds during build:
{
"scripts": {
"build": "yarn velite build && next build && yarn rss:build",
"rss:build": "node -r esbuild-register rss.ts"
}
}
RSS Feed Page
We created a dedicated page for the RSS feeds at /rss
that provides links to all available feed formats:
import Link from "next/link";
import { Rss } from "lucide-react";
import PageHeader from "@/components/page-header";
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export default function RSSPage() {
return (
<div className="container relative max-w-4xl py-6 lg:py-10">
<PageHeader
title="RSS Feeds"
description="Subscribe to subaud using your favorite RSS reader"
/>
<hr className="my-8" />
<div className="prose dark:prose-invert">
<h2>Available Feeds</h2>
<div className="space-y-4">
<div className="flex items-center space-x-2">
<Rss className="h-4 w-4" />
<Link
href="/rss.xml"
className={cn(buttonVariants({ variant: "link" }), "pl-0")}
>
RSS Feed
</Link>
<span className="text-muted-foreground">(RSS 2.0 format)</span>
</div>
<div className="flex items-center space-x-2">
<Rss className="h-4 w-4" />
<Link
href="/atom.xml"
className={cn(buttonVariants({ variant: "link" }), "pl-0")}
>
Atom Feed
</Link>
<span className="text-muted-foreground">(Atom 1.0 format)</span>
</div>
<div className="flex items-center space-x-2">
<Rss className="h-4 w-4" />
<Link
href="/feed.json"
className={cn(buttonVariants({ variant: "link" }), "pl-0")}
>
JSON Feed
</Link>
<span className="text-muted-foreground">(JSON Feed format)</span>
</div>
</div>
</div>
</div>
);
}
Navigation
We added a "Feed" link to the main navigation by updating our NAV_LIST
constant:
export const NAV_LIST = [
{ label: "Search", path: "/blog", icon: Search },
{ label: "Categories", path: "/categories", icon: Icons.categories },
{ label: "Feed", path: "/rss", icon: Icons.rss },
// ... other navigation items
];
Available Formats
The blog now provides feeds in three formats:
- RSS 2.0 (
/rss.xml
) - Atom 1.0 (
/atom.xml
) - JSON Feed (
/feed.json
)
These feeds are automatically generated during the build process and are available as static files in the exported site.
Conclusion
By implementing RSS feeds, we've made it easier for readers to stay updated with new blog posts using their preferred feed reader. The feeds are generated statically during build time, which keeps our site fast and simple while providing this essential functionality.