RSS σε 66 κοινωνικά δίκτυα: Facebook, Instagram, X, LinkedIn, Telegram και άλλα Blog Συνεργατικό Πρόγραμμα Επικοινωνία
Σύνδεση Ξεκινήστε δωρεάν
Updated: 2026-10-15
Fastify RSS Feed: Build a Fast Node.js Route and Auto-Post

Short answer: A Fastify RSS feed is a single GET route. Load the newest published posts, build RSS 2.0 XML with escaped text and absolute links, and send it with reply.type('application/rss+xml; charset=utf-8').send(xml). Add a short Cache-Control header, compress the response and validate the output once. Then paste the feed address into an auto-poster, and every new post is shared on your social channels without any manual work.

Fastify is a Node.js web framework known for low overhead and a clean plugin system. It does not include a feed generator, and it does not need one: an RSS feed is only a response with a special content type. This guide shows a complete route, a PostgreSQL data source, caching, compression, error handling and the mistakes that most often break feeds. At the end you will see how to share each item automatically.

Why a feed is just a route in Fastify

An RSS document is plain XML served over HTTP. Fastify already handles routing, headers and serialization, so the only decisions are where the posts come from and how to turn them into XML. The data can live in a SQL database, a document store, Markdown files or an upstream API. If your content sits 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.

If you have built feeds in other Node.js frameworks, the pattern will be familiar from the Express RSS feed guide. The difference in Fastify is mostly in the reply API and in how plugins are registered.

The route handler

This example uses the official PostgreSQL plugin and a table named posts with the columns id, slug, title, summary, image, published_at και status:

import Fastify from 'fastify';
import postgres from '@fastify/postgres';

const SITE = 'https://www.example.com';
const app = Fastify({ logger: true });

await app.register(postgres, { connectionString: process.env.DATABASE_URL });

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

app.get('/rss.xml', async (request, reply) => {
  const { rows } = await app.pg.query(
    'SELECT id, slug, title, summary, image, published_at FROM posts '
    + 'WHERE status = $1 ORDER BY published_at DESC LIMIT $2',
    ['published', 20]
  );

  const items = rows.map((post) => {
    const link = SITE + '/blog/' + post.slug;
    const image = post.image ? new URL(post.image, SITE).href : '';
    return '<item>'
      + '<title>' + esc(post.title) + '</title>'
      + '<link>' + esc(link) + '</link>'
      + '<guid isPermaLink="false">post-' + post.id + '</guid>'
      + '<pubDate>' + new Date(post.published_at).toUTCString() + '</pubDate>'
      + '<description>' + esc(post.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>';

  return reply
    .type('application/rss+xml; charset=utf-8')
    .header('Cache-Control', 'public, max-age=300')
    .send(xml);
});

await app.listen({ port: 3000, host: '0.0.0.0' });

The handler is asynchronous and returns the reply, which is the style Fastify recommends. The feed is available at /rss.xml as soon as the server starts. Replace the query with your own data access if you do not use PostgreSQL; everything below the query stays the same.

Why each line 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 and auto-posters stop at the first error. If your summaries contain HTML, escape them or wrap them in CDATA; the rules are described in CDATA and HTML in RSS descriptions.

The query filters on status and sorts by published_at, newest first, with a limit of 20. A feed does not need your whole archive, and a short feed is fetched faster. Always sort by the publication date, not by the update date, otherwise an edited old post jumps to the top and may look new.

The GUID uses the database ID. If you used the slug instead, renaming a post would create a new identifier and an auto-poster could share the article twice; see why your RSS feed auto-posts the same article twice. Dates are written with toUTCString(), which produces the RFC 822 format that RSS expects. Typical date mistakes are covered in RSS date formats and pubDate errors.

Compression and ETags with plugins

Feeds are fetched often, and the XML compresses very well. Two official plugins handle this without changing the route:

  • @fastify/compress adds gzip or Brotli encoding when the client accepts it. Register it before the route and the feed is sent compressed.
  • @fastify/etag adds an ETag header to responses, so a client that sends a conditional request can receive a short 304 reply when nothing has changed.

Both reduce traffic without any effect on the content. The background is explained in RSS feed compression with gzip and Brotli and in RSS feed ETags and conditional GET.

Caching the feed

The data in a feed changes rarely, but the feed is requested constantly by readers, crawlers and auto-posters. You have three layers to choose from:

  • The Cache-Control header in the example lets browsers, proxies and a CDN reuse the response for five minutes.
  • An in-memory copy of the generated XML inside the Node.js process, refreshed after a short time, keeps the database out of the picture for most requests.
  • A reverse proxy cache such as the one built into a web server can serve the file without touching Node.js at all.

Keep the lifetime short. A feed cached for a whole day delays every share by a day, which defeats the purpose of automation. Five minutes is a sensible balance for most blogs.

Error handling that protects your readers

If the database is unavailable, an unhandled error returns a JSON error object with status 500. A feed reader or auto-poster that receives it will treat the feed as broken and may retry aggressively. A safer pattern is to catch the failure, log it and return a 503 status with a Retry-After header, so clients know the problem is temporary:

try {
  // build and send the feed
} catch (err) {
  request.log.error(err);
  return reply.code(503).header('Retry-After', '120').type('text/plain').send('Feed temporarily unavailable');
}

The meaning of each status code for auto-posting is described in RSS feed HTTP status codes explained. Never return an empty but valid feed as a fallback: an empty channel looks like a healthy feed with no news, and nothing will warn you.

Absolute links and images

Items are read outside your website, so every address must be complete. A relative link such as /blog/my-post or an image path such as /img/cover.jpg works in a browser on your site but fails in a reader or on a social network. The call new URL(path, SITE) turns a relative image path into an absolute one and keeps addresses that are already absolute. This class of mistake is described in relative URLs in RSS feeds.

Choose images about 1200 pixels wide and set the correct type for each file instead of hard-coding JPEG when your covers can also be PNG or WebP. Sizes for each network are listed in social media image sizes.

One feed per category

Fastify routes accept parameters, so one handler can serve a feed for every category. Register app.get('/category/:name/rss.xml', ...), read the value from request.params.name and add a category = $3 condition to the query. Always pass the value as a parameter, never as part of the SQL text. Move the XML builder into a function that takes a title and a list of posts, and reuse it for the main feed and for each category.

Separate feeds let you send news to one channel, tutorials to another and announcements to a team chat, instead of publishing everything everywhere. The idea is explained in category filtering for auto-posting.

Running behind a proxy or a load balancer

Production Node.js applications usually sit behind a reverse proxy, a load balancer or a platform router. Two details matter for feeds. First, build every link from the fixed SITE constant rather than from the incoming host header, otherwise the feed may contain an internal address or an http link when your public address is https. Second, if you do read the client address or protocol, start Fastify with the trustProxy option so that it trusts the headers your proxy adds. Finally, make sure the proxy does not strip or rewrite the content type and does not apply its own long cache to the route. A quick check from outside your network, after every deployment, catches most of these problems before an auto-poster does.

Common mistakes to avoid

  • Sending the XML with the wrong type. Fastify sends a string as text/plain unless you set a type. Always call reply.type() with application/rss+xml; see the Content-Type guide.
  • Whitespace before the XML declaration. The declaration must be the first characters of the document; see fixing the XML declaration error.
  • Using the server time zone for dates. Convert to UTC so every reader sees the same moment.
  • Publishing drafts by accident. Filter on the status in the query, not in a template.
  • Building the feed on every request without limits. A popular feed can generate thousands of identical database queries a day. Cache it.
  • 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 post is first and that no draft appears.
  3. Open several item links and image addresses; they must use your public https domain, not a local address.
  4. Run the feed through the W3C Feed Validation Service.
  5. Request the feed from the deployed address, because a local server may behave differently behind a proxy.

The framework and its plugins are documented at fastify.dev.

How PostRSS works with a Fastify 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.

Σχετική ανάγνωση

The bottom line

A Fastify RSS feed is a single GET route that returns XML. Load the newest published posts, escape every text value, use a stable ID for the GUID, make links and images absolute and send the content type application/rss+xml with a short cache lifetime. Add compression and ETags with official plugins, answer failures with a 503 status and validate the result once. After that, every post you publish can reach your social channels automatically.

FAQ

Does Fastify have a built-in RSS feed generator?

No. Fastify is a general web framework. You add the feed as a normal route that builds RSS XML from your posts and returns it with the correct content type.

Which address should the feed have?

Any address works. The names /rss.xml and /feed.xml are common. You can also add a link tag with the type application/rss+xml to your page head so that readers and tools can discover the feed.

Should I use a plugin or write the XML by hand?

For a simple blog, a short function that builds the XML is easy to read and has no extra dependency. If you need many options, a feed library can help, but you still need to set the content type and the cache headers yourself.

Why does my feed download instead of opening in the browser?

Many browsers offer to download files of the type application/rss+xml. That is normal. Use curl or a validator to inspect the content, and test the address in your auto-poster.

Can I use the Fastify 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 Fastify have a built-in RSS feed generator?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “No. Fastify is a general web framework. You add the feed as a normal route that builds RSS XML from your posts and returns it with the correct content type.”}}, {“@type”: “Question”, “name”: “Which address should the feed have?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Any address works. The names /rss.xml and /feed.xml are common. You can also add a link tag with the type application/rss+xml to your page head so that readers and tools can discover the feed.”}}, {“@type”: “Question”, “name”: “Should I use a plugin or write the XML by hand?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “For a simple blog, a short function that builds the XML is easy to read and has no extra dependency. If you need many options, a feed library can help, but you still need to set the content type and the cache headers yourself.”}}, {“@type”: “Question”, “name”: “Why does my feed download instead of opening in the browser?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Many browsers offer to download files of the type application/rss+xml. That is normal. Use curl or a validator to inspect the content, and test the address in your auto-poster.”}}, {“@type”: “Question”, “name”: “Can I use the Fastify 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.

Περισσότερα εργαλεία από την ομάδα μας

Από την Internet Solutions, την ομάδα πίσω από το PostRSS. Κάθε προϊόν σάς εξοικονομεί χρόνο με τον δικό του τρόπο.

Live chat με AI για ιστότοπους Talkmio Ο ιστότοπός σας απαντά στους επισκέπτες 24/7 με βάση το δικό σας περιεχόμενο, στη γλώσσα τους. Δωρεάν πρόγραμμα · χωρίς κάρτα Βοηθός AI Ask Mio Συνομιλία, κώδικας, σχεδιασμός, γραφή και έρευνα. Το Mio επιλέγει το καλύτερο μοντέλο για κάθε εργασία. Δωρεάν πρόγραμμα Αυτόματος πιλότος AI για blog και social AI Blog Autopilot Η AI γράφει άρθρα SEO 2.000–3.000 λέξεων και κοινοποιεί το καθένα σε 60 κοινωνικά δίκτυα. Τα 3 πρώτα άρθρα δωρεάν Έλεγχος υγείας ιστότοπου Έλεγχος AI ιστοτόπου SEO, ταχύτητα, SSL, ασφάλεια και ρυθμίσεις email σε μία αναφορά, με σειρά προτεραιότητας. Ο πρώτος έλεγχος δωρεάν Σε βάθος ανίχνευση SEO Έλεγχος SEO AI ιστοτόπου Πλήρης ανίχνευση SEO σε 7 τομείς, μαζί με την ορατότητα στην αναζήτηση AI, με διορθώσεις ταξινομημένες κατά αντίκτυπο. Ο πρώτος έλεγχος δωρεάν RSS και ροές προϊόντων Δημιουργός RSS Feed Δημιουργήστε RSS από οποιαδήποτε σελίδα, καθώς και ροές προϊόντων για Google και Meta που ενημερώνονται μόνες τους. Δωρεάν πρόγραμμα Ανάπτυξη ιστότοπων και SEO Internet Solutions Ιστότοποι, ηλεκτρονικά καταστήματα και εξατομικευμένα συστήματα, που σχεδιάζει, κατασκευάζει και υποστηρίζει η ομάδα μας. Από το 2011