RSS ไปยังโซเชียลเน็ตเวิร์ก 66 แห่ง: Facebook, Instagram, X, LinkedIn, Telegram และอื่นๆ บล็อก พันธมิตร (Affiliate) ติดต่อเรา
เข้าสู่ระบบ เริ่มต้นใช้งานฟรี
Updated: 2026-10-06
NestJS RSS Feed: Build a Feed Endpoint and Auto-Post Posts

Short answer: NestJS has no feed module of its own, but a NestJS RSS feed is a single controller method. Load the latest published posts through your service, build the XML with the feed package, set the Content-Type header to application/rss+xml with the @Header() decorator and return the string. Use a fixed site URL for absolute links, cache the response for a few minutes, and the feed is ready for readers and for automatic social posting.

NestJS is a common choice for TypeScript back ends: content APIs behind React or Vue front ends, company portals, marketplaces and blogs built on a custom data model. Because Nest is designed around JSON APIs, the RSS feed is easy to overlook. Yet a feed is still the simplest way to tell the outside world “something new was published”, and it is the input almost every syndication and auto-posting tool expects. This guide walks through a clean implementation, the details that most often break feeds in Nest projects, and how to use the feed for social sharing.

What the feed has to deliver

A feed that works for readers, aggregators and automation tools has a short list of requirements:

  • the most recent public items, newest first, usually 20 to 50 of them;
  • for each item a title, an absolute link, a short description, a publication date and a permanent unique guid;
  • a channel title, a link to the site and a description;
  • UTF-8 output with an RSS or XML content type, served without redirects;
  • stable IDs, so that an old item is never mistaken for a new one.

Images and categories are optional, but they decide how each shared post looks, so we will add them after the basics work. For a refresher on the elements, see what guid and pubDate actually do.

Step 1: install the feed package

Building XML by string concatenation is the fastest way to ship a broken feed: one ampersand in a title and the whole document fails to parse. The feed package on npm generates RSS 2.0, Atom 1.0 and JSON Feed from one object and handles escaping for you:

npm install feed

It is written in TypeScript and ships its own types, so it fits naturally into a Nest project.

Step 2: a feed service

Keep the feed logic in a service, so the controller stays thin and the code is easy to test. The example uses TypeORM, but the same idea works with Prisma, Mongoose or any repository you already have.

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Feed } from 'feed';
import { Post } from './post.entity';

@Injectable()
export class FeedService {
  constructor(
    @InjectRepository(Post) private readonly posts: Repository<Post>,
    private readonly config: ConfigService,
  ) {}

  async buildRss(): Promise<string> {
    const site = this.config.getOrThrow<string>('SITE_URL'); // https://example.com
    const items = await this.posts.find({
      where: { published: true },
      order: { publishedAt: 'DESC' },
      take: 30,
    });

    const feed = new Feed({
      title: 'Example Blog',
      description: 'New articles from Example Blog',
      id: site + '/',
      link: site + '/',
      language: 'en',
      copyright: 'Example Ltd',
      updated: items[0]?.updatedAt ?? new Date(),
      feedLinks: { rss: site + '/feed.xml' },
    });

    for (const p of items) {
      const url = site + '/blog/' + p.slug;
      feed.addItem({
        title: p.title,
        id: url,
        link: url,
        description: p.summary,
        date: p.publishedAt,
        image: p.coverUrl ?? undefined,
        category: p.tags.map((name) => ({ name })),
      });
    }
    return feed.rss2();
  }
}

Note the id field: the package uses it as the item guid. Choose it once and never change it. Switching from numeric IDs to URLs, or from one domain to another, makes every tool that reads the feed treat all items as new; our guide on duplicate guid fixes explains why.

Step 3: the controller

The controller exposes the route and sets the headers. Without an explicit content type, Nest’s Express adapter sends a returned string as text/html, which some readers and validators reject.

import { Controller, Get, Header } from '@nestjs/common';
import { FeedService } from './feed.service';

@Controller()
export class FeedController {
  constructor(private readonly feed: FeedService) {}

  @Get('feed.xml')
  @Header('Content-Type', 'application/rss+xml; charset=utf-8')
  @Header('Cache-Control', 'public, max-age=300')
  rss(): Promise<string> {
    return this.feed.buildRss();
  }
}

Register both classes in a FeedModule, import TypeOrmModule.forFeature([Post]) and the config module, and the endpoint is live. If your app uses a global prefix such as /api, exclude the feed route from it, because a public feed is easier to find at /feed.xml than at /api/feed.xml.

Absolute URLs and reverse proxies

Every link in an RSS feed must be absolute. The example above uses a SITE_URL setting instead of reading the host from the request, and that is deliberate. A Nest app usually runs behind Nginx, a load balancer or a platform router, and the request it receives may say http://localhost:3000. Building links from that produces internal addresses or plain HTTP links in the feed.

If you do want request-based URLs, tell Express to trust the proxy:

const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.set('trust proxy', 1);

Then req.protocol และ req.hostname reflect the forwarded headers. Still, a fixed setting is more predictable in tests, queues and scheduled jobs. Check the live feed once: the first <link> should match the address visitors see. Relative links are a classic cause of broken shared posts, as explained in relative URLs in RSS feeds.

Dates, encoding and content

The feed package formats dates in the RFC 822 style that RSS requires, as long as you pass real Date objects. Problems usually come from upstream:

  • Strings instead of dates. If your ORM returns an ISO string, convert it with new Date(value) first.
  • Local time stored as UTC. Store timestamps in UTC; otherwise posts appear hours early or late in readers.
  • Control characters. Text pasted from word processors sometimes contains invisible characters that XML does not allow. Strip them when saving content.
  • HTML in descriptions. Keep description short and plain. If you want full HTML, put it in the content field, which becomes content:encoded.

More examples of what breaks are in RFC 822 pubDate errors และ feed encoding issues.

Caching and ETags

Feeds are polled frequently. Rebuilding the XML from the database for every request is wasteful, especially once several readers and tools subscribe.

  1. HTTP caching. The Cache-Control header above lets CDNs and proxies reuse the response for five minutes. Avoid hour-long caches: they delay every downstream reader and auto-poster.
  2. ETag and 304. With the Express adapter, Nest sends returned strings through Express, which adds a weak ETag and answers 304 Not Modified when the client’s If-None-Match matches. With the Fastify adapter you need the @fastify/etag plugin for the same behaviour.
  3. Application cache. If building the feed is expensive, cache the generated string with CacheModule from @nestjs/cache-manager, and clear it when a post is published. Check the TTL unit for your version; recent versions use milliseconds.

Caching too aggressively is a common reason why auto-posts lag behind publishing; see RSS feed caching explained.

Category feeds and discovery

If you publish several topics, one more route gives you a feed per category: @Get('category/:slug/feed.xml'). Reuse the same service with a filter, and throw NotFoundException for unknown categories so a mistyped feed address fails loudly instead of returning an empty feed.

Your front end should also advertise the feed. Add this to the HTML head of your pages:

<link rel="alternate" type="application/rss+xml"
      title="Example Blog" href="https://example.com/feed.xml">

Browsers, readers and many tools look for that tag to discover the feed from any page.

Test and validate

An end-to-end test with Supertest catches regressions in headers and structure:

it('serves a valid RSS feed', async () => {
  const res = await request(app.getHttpServer()).get('/feed.xml').expect(200);
  expect(res.headers['content-type']).toContain('application/rss+xml');
  expect(res.text).toContain('<rss version="2.0"');
  expect(res.text).toContain('<link>https://');
});

Then run the deployed feed through the W3C Feed Validation Service once. The NestJS controllers documentation covers the @Header() decorator and response handling in more detail.

Common NestJS feed problems

SymptomCauseFix
Feed served as text/htmlNo content type set@Header('Content-Type', 'application/rss+xml')
Feed wrapped in JSON quotesReturning an object or using a JSON interceptorReturn the XML string; exclude the route from global interceptors
Links point to localhostURLs built from the internal requestFixed SITE_URL หรือ trust proxy
Feed at /api/feed.xmlGlobal prefix appliedExclude the route from the prefix
All items reposted after a releaseChanged item IDsKeep guid values permanent
Readers update hours lateLong CDN cacheShort max-age, purge on publish

Global response interceptors deserve a second look. Many Nest projects wrap every response in an envelope such as { data: ... }. Applied to the feed, that turns valid XML into a JSON object. Skip the interceptor for this controller.

Connect the feed to social auto-posting

With a valid feed, you could write a queue worker that calls each network’s API when a post is published. In practice, every network has its own authentication, token refresh, rate limits and media rules, and they change regularly. That is a lot of code to maintain for something that is not your product. An RSS auto-poster reads the feed you already serve and publishes new items for you.

  • make sure an item appears in the feed only after its page is publicly reachable;
  • give every item an image, because posts with images get noticeably more attention;
  • use categories to send different topics to different accounts;
  • add tracking parameters in the auto-poster, not in the feed itself.

How PostRSS works with a NestJS feed

PostRSS has been turning RSS and Atom feeds into social posts since 2014. You paste the feed address, connect accounts and choose what each post contains. It checks the feed as often as every minute and publishes each new item, with its real image and link, to any of 66 supported networks, messengers, team chats and blogs. You can build posts from the title, description or static text, add UTM parameters, filter by keywords, turn categories into hashtags and set posting windows. For developers there is a REST API v1 and outgoing webhooks. Details are on the PostRSS features page, and plan limits are on the pricing page. More developer guides are under the Technical Guide tag.

Related reading

The bottom line

A NestJS RSS feed is a small service and one controller method: query recent published posts, build the XML with the feed package, set the RSS content type, and cache the result briefly. Use a fixed site URL, keep item IDs permanent, keep the route out of global prefixes and interceptors, and validate it once. After that, the feed can drive automatic sharing of everything you publish.

FAQ

Does NestJS have a built-in RSS module?

No. NestJS does not include a feed generator. You add a controller route that returns XML, usually built with the feed package from npm, which also produces Atom and JSON Feed from the same data.

Why is my NestJS feed served as text/html?

When a controller returns a string, the Express adapter sends it as HTML unless you set a content type. Add the Header decorator with application/rss+xml to the route and the feed is served correctly.

Should I build feed URLs from the request or from a setting?

A fixed site URL setting is the most reliable option, because the request inside a container often shows an internal host. If you prefer request-based URLs, enable trust proxy so forwarded headers are respected.

How do I stop old posts from being reposted?

Keep each item’s ID, which becomes the guid, permanent. Changing the ID scheme or the domain makes readers and auto-posters see every item as new.

Can I auto-post a NestJS feed to social media?

Yes. Once the feed is public and valid, an RSS auto-poster such as PostRSS can read it and publish new items to the networks you connect, with no extra code in your NestJS application.

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 แต่ละผลิตภัณฑ์ช่วยประหยัดเวลาของคุณในแบบที่ต่างกัน

แชทสด AI สำหรับเว็บไซต์ Talkmio เว็บไซต์ของคุณตอบผู้เข้าชมได้ตลอด 24 ชั่วโมงจากเนื้อหาของคุณเอง ในภาษาของพวกเขา แพ็กเกจฟรี · ไม่ต้องใช้บัตร ผู้ช่วย AI Ask Mio แชท เขียนโค้ด ออกแบบ เขียนงาน และค้นคว้า Mio เลือกโมเดลที่ดีที่สุดให้กับแต่ละงาน แพ็กเกจฟรี ระบบอัตโนมัติ AI สำหรับบล็อกและโซเชียล AI Blog Autopilot AI เขียนบทความ SEO ยาว 2,000–3,000 คำ และแชร์แต่ละบทความไปยังโซเชียลเน็ตเวิร์กกว่า 58 แห่ง 3 บทความแรกฟรี ตรวจสุขภาพเว็บไซต์ Site AI Audit SEO ความเร็ว SSL ความปลอดภัย และการตั้งค่าอีเมลในรายงานเดียว เรียงตามสิ่งที่ควรแก้ก่อน ตรวจครั้งแรกฟรี ตรวจ SEO เชิงลึก Site SEO AI Audit ตรวจ SEO ทั้งเว็บใน 7 ด้าน รวมถึงการมองเห็นในการค้นหาด้วย AI พร้อมรายการแก้ไขเรียงตามผลกระทบ ตรวจครั้งแรกฟรี ฟีด RSS และฟีดสินค้า RSS Feed Creator สร้าง RSS จากหน้าเว็บใดก็ได้ พร้อมฟีดสินค้าสำหรับ Google และ Meta ที่อัปเดตเอง แพ็กเกจฟรี พัฒนาเว็บไซต์และ SEO Internet Solutions เว็บไซต์ ร้านค้าออนไลน์ และระบบเฉพาะทาง ออกแบบ สร้าง และดูแลโดยทีมของเรา ตั้งแต่ปี 2011
PostRSS - ระบบอัตโนมัติ RSS Feed และเครื่องมือโพสต์อัตโนมัติ
ภาพรวมความเป็นส่วนตัว

เว็บไซต์นี้ใช้คุกกี้เพื่อให้เราสามารถมอบประสบการณ์การใช้งานที่ดีที่สุดแก่คุณ ข้อมูลคุกกี้จะถูกเก็บไว้ในเบราว์เซอร์ของคุณและทำหน้าที่ต่างๆ เช่น การจดจำคุณเมื่อคุณกลับมาที่เว็บไซต์ของเรา และช่วยให้ทีมงานของเราเข้าใจว่าส่วนใดของเว็บไซต์ที่คุณสนใจและมีประโยชน์มากที่สุด