RSS zu 66 sozialen Netzwerken: Facebook, Instagram, X, LinkedIn, Telegram und mehr Blog Affiliate Kontakt
Anmelden Kostenlos starten
Updated: 2026-10-15
PocketBase RSS Feed: Add a Custom Route and Auto-Post Records

Short answer: PocketBase has no built-in RSS output, but a few lines of JavaScript in the pb_hooks folder add one. Register a route with routerAdd('GET', '/rss.xml', ...), load the newest published records with $app.findRecordsByFilter, build RSS 2.0 XML with escaped text and absolute links, and return it with the content type application/rss+xml. Add a short cache header, validate the feed once and paste its address into an auto-poster so that every new published record is shared on social media automatically.

PocketBase is an open-source backend in a single executable: an embedded database, authentication, file storage, an admin dashboard and an extension system. It is popular for small apps, internal tools and personal sites, and many of them keep articles, products or announcements in a collection. Because PocketBase lets you extend it with JavaScript hooks, a feed is a small addition rather than a separate service. This guide shows the collection, the route, the points where hooks behave differently from ordinary Node.js code, caching and the checks that keep the feed reliable. At the end you will see how to share each item automatically.

Why a hook is the right tool

A feed is an HTTP response containing XML. PocketBase already runs a web server, and its JavaScript extension layer lets you add custom routes that run inside the same process. There is no need for a second server or a separate deployment, and the feed shares the host name and the certificate of your PocketBase instance. If your content lives in a system without a native feed, the idea is the same as in auto-posting from a headless CMS without native RSS: build the feed yourself and let the auto-poster read it.

This guide targets recent PocketBase versions, from 0.23 onward, in which route handlers receive a single event object. Older versions used a different handler signature, so check the documentation for the version you run.

The collection

Create a collection named posts with the fields title (text), slug (text), summary (text), cover (file, optional), published_at (date) and status (text or select with values such as draft and published). Content editors can then work in the dashboard, and only records with the status published will appear in the feed.

Hooks run with full access to the application, so the API rules of the collection do not limit what the code can read. That is convenient, but it also means your code must do the filtering. Never rely on the collection rules to hide drafts from a feed that you build by hand.

The route

Create the file pb_hooks/rss.pb.js next to the PocketBase executable:

routerAdd('GET', '/rss.xml', (e) => {
  const SITE = 'https://www.example.com';
  const PB = 'https://cms.example.com';

  const esc = (value) => String(value || '')
    .replace(/&/g, '&')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');

  const records = $app.findRecordsByFilter(
    'posts',
    "status = 'published'",
    '-published_at',
    20,
    0
  );

  const items = records.map((post) => {
    const link = SITE + '/blog/' + post.getString('slug');
    const cover = post.getString('cover');
    const image = cover ? PB + '/api/files/posts/' + post.id + '/' + cover : '';
    const date = new Date(post.getString('published_at').replace(' ', 'T'));
    return '<item>'
      + '<title>' + esc(post.getString('title')) + '</title>'
      + '<link>' + esc(link) + '</link>'
      + '<guid isPermaLink="false">post-' + post.id + '</guid>'
      + '<pubDate>' + date.toUTCString() + '</pubDate>'
      + '<description>' + esc(post.getString('summary')) + '</description>'
      + (image ? '<enclosure url="' + esc(image) + '" type="image/jpeg" length="0"/>' : '')
      + '</item>';
  });

  const xml = '<?xml version="1.0" encoding="UTF-8"?>'
    + '<rss version="2.0"><channel>'
    + '<title>Example Blog</title>'
    + '<link>' + SITE + '/blog</link>'
    + '<description>News and articles from Example</description>'
    + items.join('')
    + '</channel></rss>';

  e.response.header().set('Content-Type', 'application/rss+xml; charset=utf-8');
  e.response.header().set('Cache-Control', 'public, max-age=300');
  return e.string(200, xml);
});

Restart PocketBase after saving the file. The feed is then available at /rss.xml on the same address as the dashboard, for example https://cms.example.com/rss.xml.

Things that behave differently in PocketBase hooks

PocketBase runs hooks in an embedded JavaScript engine, not in Node.js or a browser. Four differences matter when you write a feed:

  • Handlers are isolated. A variable or function declared at the top of the file is not visible inside the handler. That is why the constants and the esc helper are defined inside it. To share code between handlers, put it in a module and load it with require inside the handler.
  • There is no browser or Node.js API set. Functions such as URL oder fetch may not exist. Build addresses with simple string concatenation, as in the example.
  • Dates are strings. A date field is returned as text such as 2026-10-15 08:00:00.000Z. Replace the space with a T before creating a Date object, and always test the result.
  • The file address is built by hand. Uploaded files are served at a predictable path made of the collection name or ID, the record ID and the file name.

Why each part matters

The helper esc converts ampersands and angle brackets into entities. Without it, a title such as “Tips & tricks” produces invalid XML and many readers stop at the first error. If your summaries contain HTML, escape them or wrap them in CDATA; the rules are in CDATA and HTML in RSS descriptions.

The filter keeps drafts out, and the sort puts the newest record first with a limit of 20. Sort by the publication date, not by the update date, so that an edited old record does not jump to the top. The GUID uses the record ID, which never changes. If you used the slug and later renamed a post, an auto-poster could share it twice; see why your RSS feed auto-posts the same article twice. Dates use toUTCString(), which produces the RFC 822 format that RSS expects, as described in RSS date formats and pubDate errors.

Absolute links and images

Items are read outside your website, so every address must be complete. A relative link or image path works in a browser on your site but fails in a reader or on a social network. In the example, the article link is built from the public address of the front end, and the image address from the public address of PocketBase. Problems of this kind are described in relative URLs in RSS feeds. Choose images about 1200 pixels wide, and set the type according to the real file. Sizes for each network are listed in social media image sizes.

Caching and the reverse proxy

PocketBase does not cache custom routes for you, and a feed is requested constantly by readers, crawlers and auto-posters. The header in the example lets browsers and proxies reuse the response for five minutes. In production, PocketBase usually sits behind a reverse proxy such as Caddy or Nginx that terminates https. You can let the proxy cache the feed for a few minutes, or compress it, without touching the hook; see RSS feed compression with gzip and Brotli. Keep the lifetime short: a feed cached for a day delays every share by a day.

One feed per category

The route can read query parameters with e.request.url.query().get('category'). If a value is present, add a condition to the filter using a parameter placeholder, for example category = {:cat}, and pass the value as an object in the extra argument. Never insert the value directly into the filter text. Move the XML builder into a module, and serve one feed for everything and one for each category. Separate feeds let you send news to one channel, tutorials to another and announcements to a team chat. The idea is explained in category filtering for auto-posting.

Deploying the feed in production

A feed that works on your laptop can still fail in production, so check three things after deployment. First, the hook file must be copied to the pb_hooks folder of the server, not only to your development folder, and the service must be restarted. Second, the public addresses in the code must match the real domains, with https and without a trailing slash, because a feed that points to localhost or to an internal host name is useless to a reader. Third, the reverse proxy must pass the request through to PocketBase without adding a login page or changing the content type. When you move the instance to another host later, keep the feed address stable or leave a permanent redirect, because every reader and auto-poster that stored the old address will keep asking for it.

Common mistakes to avoid

  • Using outer variables in the handler. They are not visible, and the route fails with an error. Define everything inside, or load a module.
  • Forgetting to filter drafts. Hooks bypass the collection rules, so the filter in your code is the only protection.
  • Returning HTML or JSON by mistake. Set the content type to application/rss+xml; see the Content-Type guide.
  • Bad date handling. Test with a real record and read the pubDate in the output.
  • Relative image paths. Build full addresses for files.
  • Changing the GUID later. A new GUID makes an old post look new and can trigger a repeat share.

Test the feed before connecting it

  1. Request the feed with curl -i and check that the status is 200 and the content type is application/rss+xml. The method is described in debugging an RSS feed with curl.
  2. Confirm that the newest published record is first and that no draft appears.
  3. Open several item links and image addresses; they must use your public https domain.
  4. Run the feed through the W3C Feed Validation Service.
  5. Publish a test record, wait for the cache time and check that it appears.

The extension system is documented at pocketbase.io/docs.

How PostRSS works with a PocketBase site

PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your rss.xml route, connect your accounts and choose how each post is built from the title, the description or the page title. PostRSS checks the feed as often as every minute and shares each new post, with its image and link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, including LinkedIn, X, Bluesky, Mastodon and Telegram. Keyword filters, UTM parameters, hashtags from categories and posting windows let you tune each channel, and the REST API and webhooks connect PostRSS to your own systems. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.

Weiterführende Lektüre

The bottom line

A PocketBase RSS feed is one hook file. Register a GET route, load the newest published records, escape every text value, use the record ID for the GUID, make links and images absolute and return the content type application/rss+xml with a short cache lifetime. Remember that handlers are isolated, that dates arrive as text and that your code must filter drafts. After that, every record you publish can reach your social channels automatically.

FAQ

Does PocketBase have a built-in RSS feed?

No. PocketBase provides the database, the API and the extension system. You add the feed with a small JavaScript hook that builds RSS XML from your collection.

Where do I put the hook file?

Put it in the pb_hooks folder next to the PocketBase executable, with a name that ends in .pb.js, and restart PocketBase after changing it.

Why does my variable not exist inside the handler?

Handlers run in isolation, so variables declared at the top of the file are not visible inside them. Define constants and helpers inside the handler or load them from a module with require.

Can I use the same code for several collections?

Yes. Move the XML builder into a module that takes a title and a list of records, and register one route for each collection or category.

Can I use the PocketBase feed with PostRSS?

Yes. Paste the public feed address as a source in PostRSS, connect your social accounts and each new item is posted automatically. Make sure the address opens without a login first.

{“@context”: “https://schema.org”, “@type”: “FAQPage”, “mainEntity”: [{“@type”: “Question”, “name”: “Does PocketBase have a built-in RSS feed?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “No. PocketBase provides the database, the API and the extension system. You add the feed with a small JavaScript hook that builds RSS XML from your collection.”}}, {“@type”: “Question”, “name”: “Where do I put the hook file?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Put it in the pb_hooks folder next to the PocketBase executable, with a name that ends in .pb.js, and restart PocketBase after changing it.”}}, {“@type”: “Question”, “name”: “Why does my variable not exist inside the handler?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Handlers run in isolation, so variables declared at the top of the file are not visible inside them. Define constants and helpers inside the handler or load them from a module with require.”}}, {“@type”: “Question”, “name”: “Can I use the same code for several collections?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Yes. Move the XML builder into a module that takes a title and a list of records, and register one route for each collection or category.”}}, {“@type”: “Question”, “name”: “Can I use the PocketBase feed with PostRSS?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Yes. Paste the public feed address as a source in PostRSS, connect your social accounts and each new item is posted automatically. Make sure the address opens without a login first.”}}]}

New guides, once a month

What changed in the networks, what broke, and how to fix it before it costs you reach.

We send a confirmation e-mail first. Unsubscribe any time.

Mehr Tools von unserem Team

Entwickelt von Internet Solutions, dem Team hinter PostRSS. Jedes Produkt spart Ihnen auf seine Weise Zeit.