News

Because I don't do social media.

Next.js dynamic RSS feed

A dynamic RSS feed example for Next.js.

February, 2021

tl;dr; Check out Markdown Blog Next.js Boilerplate for a full-fledged example!

Most examples of RSS feeds for Next.js are focused on the pages you know you have at build/deploy time, but what about something like a blog with a CMS where you won't build or deploy every time there's a new article? Or even for ecommerce, where you don't usually want or need to build your website every time you're adding new product or editing an existing one?

So that's what this example focuses on. An RSS feed for "truly dynamic content". Content that potentially doesn't yet exist at build time. And the feed will be generated on-request, so it's truly dynamic, not a file inside the public directory.

For that, you can create a simple file, pages/rss.xml.ts (can also be pages/rss.xml.js if you're not using TypeScript):

import { GetServerSideProps } from 'next';
import { Feed } from 'feed';
import moment from 'moment';

// NOTE: This should be a function or imported method that makes a call to the backend.
const getAllArticles = async () => {
  return [
    {
      slug: 'example'
      title: 'Some Example',
      summary: 'Just a simple summary.',
      date: '2021-02-23',
    },
  ];
};

const hostUrl = 'https://example.com';

const buildFeed = (items) => {
  const feed = new Feed({
    id: hostUrl,
    link: hostUrl,
    title: 'Your website title',
    description: 'Some description for your website.',
    copyright: "These are mine, but you're welcome to share them.",
    updated: moment(items[0].date, 'YYYY-MM-DD').toDate(),
    author: {
      name: 'Bruno Bernardino',
      link: hostUrl,
    },
  });

  items.forEach((item) => {
    feed.addItem({
      title: item.title,
      link: `${hostUrl}/article/${item.slug}`,
      description: item.summary,
      date: moment(item.date, 'YYYY-MM-DD').toDate(),
    });
  });

  return feed;
};

export const getServerSideProps: GetServerSideProps = async (context) => {
  if (context && context.res) {
    const { res } = context;

    const articles = await getAllArticles();

    const feed = buildFeed(articles);
    res.setHeader('content-type', 'text/xml');
    res.write(feed.rss2()); // NOTE: You can also use feed.atom1() or feed.json1() for other feed formats
    res.end();
  }

  return {
    props: {},
  };
};

const RssPage = () => null;

export default RssPage;

NOTE: The code above assumes Next.js v9.4 or above. For earlier versions you don't have getServerSideProps but you could make due with getInitialProps.

NOTE 2: I mostly talk about RSS, but this could also be used for Atom or JSON feeds. Check the comments in the code.

After you install the dependencies (you could rewrite the above to not use moment, but you should install feed, i.e. npm install feed).

Now you can try that out by simply going to /rss.xml on your website.

Do not forget to add in your <head> section the appropriate reference to the feed(s), like:

<link rel="alternate" type="application/rss+xml" href="/rss.xml" />
<link rel="alternate" type="application/atom+xml" href="/atom.xml" />
<link rel="alternate" type="application/json" href="/feed.json" />

In my Markdown Blog Next.js Boilerplate you can find a full-fledged working example.

Thank you for your attention and kindness. I really appreciate it!