I recently decided to add an RSS feed to my blog. Like any developer, my first instinct was to Google "how to add RSS feed to Next.js blog" 😄
During my research, I found that many tutorials suggested using the rss
npm package. One particular tutorial by Dave Gray caught my attention. It seemed straightforward enough, so I decided to give it a try.
However, things didn't go quite as planned. Despite following the tutorial, I ran into some issues getting it to work with my Next.js App Router setup. That's when I remembered that I had already implemented a sitemap for my blog using Next.js's built-in features without any external packages. After some experimentation with route handlers and XML generation, I managed to get it working!
Here's how I implemented it using Next.js App Router's route handlers, no external packages needed.
Basic Structure
// app/feed/route.ts
export async function GET() {
const blogs: Blogs = await getMetadata()
// Generate and return RSS XML
}
This creates a route handler at /feed
that responds to GET requests. We use getMetadata()
to fetch all blog posts.
XML Generation
1. XML Header and Channel Info
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>realvjy's story</title>
<link>https://story.vjy.me</link>
<description>Some thoughts, stories and insights</description>
<language>en</language>
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
- Defines XML version and encoding
- Specifies RSS version 2.0
- Includes atom namespace for enhanced compatibility
- Sets channel metadata (title, link, description)
- Uses
toUTCString()
for standard date format
2. Blog Posts Processing
Object.entries(blogs)
.sort(([, a], [, b]) =>
new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
)
.map(([id, blog]) => {
const url = `https://story.vjy.me/${id}`;
// Generate item XML
})
- Converts blog object to array of entries
- Sorts posts by date (newest first)
- Maps each blog post to RSS item format
3. Individual Post Items
<item>
<title><![CDATA[${blog.title}]]></title>
<link>${url}</link>
<guid>${id}</guid>
<description><![CDATA[${blog.description}]]></description>
<pubDate>${new Date(blog.created_at).toUTCString()}</pubDate>
<author>${blog.author_id}</author>
<category>${blog.category}</category>
</item>
CDATA
sections protect against special characters in title and descriptionguid
uses post ID for unique identificationpubDate
converts blog date to UTC format- Includes author and category information
4. Response Headers
return new Response(xml, {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, max-age=3600'
}
})
- Sets proper XML content type
- Enables caching for one hour
- Returns RSS feed as HTTP response
Usage Example
When a reader visits /feed, they'll receive an RSS feed like this:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>realvjy's story</title>
<link>https://story.vjy.me</link>
<description>Some thoughts, stories and insights</description>
<item>
<title>
<![CDATA[ Adding RSS Feed to Next.js blog ]]>
</title>
<link>https://story.vjy.me/28</link>
<guid isPermaLink="false">28</guid>
<description>
<![CDATA[ How I implemented RSS feed using Next.js App Router's route handlers instead of external packages. ]]>
</description>
<pubDate>Fri, 13 Dec 2024 18:30:00 GMT</pubDate>
<author>realvjy</author>
<category>Devlog</category>
</item>
<!-- More items... -->
</channel>
</rss>
This implementation provides a standard-compliant RSS feed that works with all major RSS readers while being efficient and maintainable. Check complete code gist here
stay hungry, stay foolish
-Steve Jobs
©realvjy✦vijay verma