Skip to content

How to add RSS feed to nuxt 3

When it comes to developing digital products like websites and information portals there are always common features that should implement in order to help the sharing and spreading of information, one of these features is RSS feeds.

What is an RSS feed

RSS stands for Really Simple Syndication, and as its full name suggests, it is a simple, standardised content distribution method that can help users stay up-to-date with with their favourite newscasts, blogs, websites, and social media channels.

Various Web platforms usually use RSS feeds to publish frequently updated information, such as news headlines, articles, episodes of audio and video series, or for distributing podcasts.  Which enables other connected platforms to keep up to date once new content is made available.

RSS was really popular in its heydays of the early 00's and there were all sorts applications that enabled users to make use of this form of syndication, but it is largely overlooked and under appreciated by the consumer market these days, that it is very often completely forgotten about. However, RSS is still very much useful and in my opinion still very much a great feature to implement in new applications.

Is Rss still used?

This is really an interesting question, because while its true that the glory days of rss have undoubtedly passed and the perception that most people make use of Social Media platforms to curate their news feeds. My own experience is that it is still possible to generate significant traffic to your site if you provide an RSS Feed. A fairly significant proportion of the traffic to this blog, is actually generated by people coming in from various RSS Reader platforms like:

It actually also surprises me that a number of users also still use their Email Clients to manage their feeds. I still get traffic from these types of clients:

Personally, I believe RSS is still really important when it comes to privacy, censorship and security. It still really matters for people who are concerned with the constant over stepping of the mark that governments, big technology companies and especially authoritarian super states.

Personally I am becoming increasingly concerned with just how much Personal Data is actually being collected by these big Social Media and Technology companies and for the most part it is completely unnecessary and real invasion of personal privacy. I have previously posted about my concerns in this area in How to Get back your online privacy Without going to far down this privacy and the corruption of big states and technology companies, I just want to highlight that making use of RSS feeds to control and curate your news feeds and interests may actually become important once more.

Mindf*ck

Inside Cambridge Analytica's Plot to Break the World

whistleblower Christopher Wylie, the definitive story of the Brexit coup, the making of Bannon's America, and an ongoing crime against democracy

Personally, I have taken the steps to actively stop using social media and actually become more selective on what to use when it is necessary to make use of and engage with social media. I have taken steps into trying ensure my websites and applications minimise as much as possible any trackers and analytics tools and in use cases where it may be beneficial to use these types of tools is to select tools that have privacy at the core of they do. For instance, when I discussed data relating to engagement of users of my websites, all this data is collected using Fathom Analytics , a privacy focused web analytics platform. I have actively tried to remove as much as possible all tracking and cookie based systems on this blog as much as possible

Benefits of RSS for bloggers

If like me you're running a blog and want to ensure that you are able to share your content as widely as possible then an RSS feed will provide the following benefits:

  1. Convenience: RSS feeds allow readers to easily access and stay updated on multiple sources of content in one place without having to visit each website individually.
  2. Increased engagement: RSS can help increase engagement with your audience by allowing readers to share your content on social media or other platforms easily. Leading to increased visibility and traffic to your blog.
  3. Search engine optimization: RSS feeds can help improve your website’s search engine rankings by providing a steady stream of fresh, relevant content. This can help increase your website’s visibility and drive more traffic to your site.

How to implement RSS Feed with Nuxt 3

Over the past few months I have been rebuilding my company website and blog using Nuxt 3 for a number of reasons but core to those are concerns over privacy and security, and also because I wanted learn and utilise Nuxt3, Vue3 and TypeScript. The source code for this tutorial can actually be viewed on the public repository of my company blog, so you will be able to watch me develop in real time as I go through this journey

One of the cool things about implementing a relatively simple RSS feed handler is that is provides you with an opportunity to learn and grasp a few features and concepts within Nuxt 3 in order to implement it.

For this example, I am going to assume you are making use of the Nuxt Content Module to generate content for your website check out How to use the Nuxt 3 Content Module for instruction on how to get started with this module

To implement the RSS feed we are going to make use of handlers that are hosted in the server directory

What is the Nuxt3 server directory

The file and folder structure of a nuxt project are really important for assisting you with code organisation, maintenance and debugging. The Nuxt3 folder structure has been carefully planned out and implemented. Check out Understanding Nuxt 3 minimal project structure to gain an overview of the various folders available in Nuxt 3 and their purposes.

The server folder contains all files needed on the server side of your Nuxt 3 application. This includes apis , server middleware, server routes, server plugins and server utilities.

If a server folder is not already present in your directory structure create it the root folder of your project directory

The server directory can then have a number of sub directories

  • api
  • routes
  • middleware
  • plugins

For the purpose of this article we are going to focus on the routes directory. Therefore, inside your server directory create another folder of named routes

We can create a TypeScript file within our routes directory and we will simply call it rss.xml.ts and we'll add the minimum required code to get our file to work.

export default defineEventHandler(() => 'RSS Feed coming soon!');

We can now run our application and navigate to our http://localhost:3000/rss and see our route in action

In order to generate our RSS feed we are going to make use of the node-rss package, which has become my preferred package as it is really simple to use and for the most part supports all the features and properties I generally require.

We can simply add the dependency to our project using your preferred package manager, personally I still use yarn

 yarn add rss

With our dependency successfully added we can now edit our rss.xml.ts file and import the 2 dependencies we are going to use for our handler

import { serverQueryContent } from '#content/server';
import RSS from 'rss';
export default defineEventHandler(() => 'RSS Feed coming soon!');

We can now get to the the real coding our solution. In this example, I have created an application configuration schema within my nuxt app that I use store common configuration properties that are used throughout the application for various things. So the first thing I want to do in my EventHandler is ensure I retrieve these values. We can do so by simply making use of the useAppConfig function within nuxt. We also want to make use of async on the event argumment

 import { serverQueryContent } from '#content/server';
import RSS from 'rss';
import {serverQueryContent} from '#content/server';
// @ts-ignore
import RSS from 'rss';

export default defineEventHandler(async (event) => {
    const config = useAppConfig()
}

We are now ready to configure out feed, which we will do by defining a variable with the name of feed and instantiating it as an RSS object using the object we imported initially into our file. We will set various properties of the feed object to values we will get from our configuration file.

These properties should be fairly self explanatory, however the ReadMe in the repository of node-rss actually does a failrly decent job of explaining these properties and their expected values.

import {serverQueryContent} from '#content/server';
// @ts-ignore
import RSS from 'rss';

export default defineEventHandler(async (event) => {
    const config = useAppConfig()

    const feed = new RSS({
        title: config.threenine.name,
        description: config.threenine.description,
        webMaster: config.threenine.webMaster,
        copyright: '${new Date().getFullYear()} ${ config.threenine.name }' ,
        site_url: '${config.threenine.site_url}',
        feed_url: '${config.threenine.site_url}/rss',
        language: 'en',
        categories: [buildCategoriesString(config.threenine.categories)]
    });
}

Now we are ready to retrieve a list of posts that we have within of application. This is where we will make use of the Nuxt Content Module and the functionality it provides for us to query content. This is where we will make use of the async functionality.

import {serverQueryContent} from '#content/server';
// @ts-ignore
import RSS from 'rss';

export default defineEventHandler(async (event) => {
    const config = useAppConfig()

     const feed = new RSS({
        title: config.threenine.name,
        description: config.threenine.description,
        webMaster: config.threenine.webMaster,
        copyright: '${new Date().getFullYear()} ${ config.threenine.name }' ,
        site_url: '${config.threenine.site_url}',
        feed_url: '${config.threenine.site_url}/rss',
        language: 'en',
        categories: [buildCategoriesString(config.threenine.categories)]
    });

    const docs = await serverQueryContent(event)
        .sort({ date: -1 })
        .where({ _partial: false })
        .find();
}

Then finally we simply want to iterate through the results of the query and append the values to our feed items.

import {serverQueryContent} from '#content/server';
// @ts-ignore
import RSS from 'rss';

export default defineEventHandler(async (event) => {
    const config = useAppConfig()

     const feed = new RSS({
        title: config.threenine.name,
        description: config.threenine.description,
        webMaster: config.threenine.webMaster,
        copyright: '${new Date().getFullYear()} ${ config.threenine.name }' ,
        site_url: '${config.threenine.site_url}',
        feed_url: '${config.threenine.site_url}/rss',
        language: 'en',
        categories: [buildCategoriesString(config.threenine.categories)]
    });

    const docs = await serverQueryContent(event)
        .sort({ date: -1 })
        .where({ _partial: false })
        .find();

    const blogPosts = docs.filter((doc) => doc?._path?.includes('/posts'));
    for (const doc of blogPosts) {
        feed.item({
            title: doc.title ?? '-',
            url: '${config.threenine.site_url}${doc._path}',
            date: doc.date,
            description: doc.description,
            author: doc.author,
            categories: [doc.category]
        });
    }
}

Now finally we would like to write our results out the Response stream.

import {serverQueryContent} from '#content/server';
// @ts-ignore
import RSS from 'rss';

export default defineEventHandler(async (event) => {
    const config = useAppConfig()

   const feed = new RSS({
        title: config.threenine.name,
        description: config.threenine.description,
        webMaster: config.threenine.webMaster,
        copyright: '${new Date().getFullYear()} ${ config.threenine.name }' ,
        site_url: '${config.threenine.site_url}',
        feed_url: '${config.threenine.site_url}/rss',
        language: 'en',
        categories: [buildCategoriesString(config.threenine.categories)]
    });

    const docs = await serverQueryContent(event)
        .sort({ date: -1 })
        .where({ _partial: false })
        .find();

    const blogPosts = docs.filter((doc) => doc?._path?.includes('/posts'));
    for (const doc of blogPosts) {
        feed.item({
            title: doc.title ?? '-',
            url: '${config.threenine.site_url}${doc._path}',
            date: doc.date,
            description: doc.description,
            author: doc.author,
            categories: [doc.category]
        });
    }

    const feedString = feed.xml({ indent: true });
    event.node.res
    event.node.res.setHeader('content-type', 'text/xml');
    event.node.res.end(feedString);
}

We should now be able to run the application and view the results. In the case of this example you will be able to view the results directly on the web by navigating to https://threenine.blog/rss.xml

This should work, but there is one final bit of configuration to do depending on your hosting provider. We should configure our nuxt application on a static server in universal mode. To do so we just need to update our nuxt.config.ts to include the following

nitro: {
    prerender: {
      routes: [ '/rss.xml' ]
    }
  }

Conclusion

In this article we configured our Nuxt3 application to have an RSS feed that will enable the syndication of your content to various platforms. RSS feeds are commonly used by publishers, bloggers, and news outlets to distribute content to their audiences.

Gary Woodfine
Latest posts by Gary Woodfine (see all)