66টি সোশ্যাল নেটওয়ার্কে RSS: Facebook, Instagram, X, LinkedIn, Telegram এবং আরও অনেক কিছু ব্লগ অ্যাফিলিয়েট যোগাযোগ
সাইন ইন ফ্রি শুরু করুন
Updated: 2026-10-26
Qwik City RSS Feed: Endpoint, Dates and ETag Caching

Short answer: To add an RSS feed to a Qwik City site, create a route folder named feed.xml with an index.ts file that exports an onGet request handler, load your published posts on the server, build the XML with CDATA-wrapped titles and summaries, and send a Response with the application/rss+xml content type. Use the publication date of each post, take the last build date from the newest post, hash the finished body into an ETag so repeat requests end in a 304, link the feed from every page, test it with curl and a validator, and give the public address to an auto-poster so new posts are shared automatically.

Qwik is built around resumability: the server renders the page, the browser downloads almost no JavaScript up front and code is loaded only when a visitor interacts. Qwik City is the routing and server layer that sits on top of it, with file-based routes, loaders, actions and endpoints. Teams pick it for fast blogs, documentation sites, shops and marketing pages. Most of those sites eventually publish things that people want to follow, such as articles, release notes or product listings, and a feed is the standard way to let readers, aggregators and auto-posters watch that content without an account or an API key. Qwik City does not ship a feed generator, and it does not need one: an endpoint is an ordinary request handler that returns whatever you want, including XML. This guide builds a complete Qwik City RSS feed with correct dates, stable identifiers and conditional requests, explains each decision and ends with the checks that keep the feed dependable once other systems rely on it.

When a Qwik City site needs a feed

A feed is worth adding whenever new items appear on a schedule you do not control: a blog, a changelog, a directory of listings or a library of guides. Readers who follow it in a feed reader get every item in order. Search engines and aggregators discover new pages faster. And an auto-poster such as PostRSS can share each new item on social networks the moment it is published, which turns a quiet publishing routine into a steady stream of visitors.

If your content already lives in a CMS that provides a feed, use that feed instead. Build the route yourself when the content comes from your own database, from markdown files or from an API without a ready-made feed. If you are comparing frameworks, the same ideas are covered in the SvelteKit RSS feed guide, the Astro guide এবং the Remix resource route guide.

How endpoints work in Qwik City

In Qwik City, a file named index.ts inside a route folder is an endpoint when it exports request handlers instead of a component. A handler named onGet runs for GET requests, onPost for POST requests, and onRequest for all methods. The handler receives a request event with the incoming request, helpers for headers and status codes, and a send function. Calling send with a standard Response object ends the request and returns that response untouched, which is exactly what a feed needs: you control the body, the status and every header.

The folder name sets the address. A folder called feed.xml inside the routes directory is served at /feed.xml, and the same pattern works for sitemap.xml or robots.txt. Nothing else in the project has to change, and the page components, layouts and loaders are not involved. This also means the feed is not wrapped in your site layout, so no HTML ever leaks into the document.

The data source

The endpoint needs a function that returns the newest published posts. The example below assumes a small module that reads from a database, but the same shape works with markdown files, a headless CMS or a REST API. The important part is the condition on the publication time: without it, a post scheduled for tomorrow would appear in the feed today, and an auto-poster would share it before it exists on the website.

// src/lib/posts.ts
export interface Post {
  slug: string;
  title: string;
  summary: string;
  publishedAt: Date;
}

export async function getPublishedPosts(limit = 20): Promise<Post[]> {
  const now = new Date();
  const rows = await db.posts.findMany({
    where: { publishedAt: { lte: now } },
    orderBy: { publishedAt: 'desc' },
    take: limit,
  });
  return rows.map((row) => ({
    slug: row.slug,
    title: row.title,
    summary: row.summary,
    publishedAt: new Date(row.publishedAt),
  }));
}

The complete endpoint

Create the file src/routes/feed.xml/index.ts. The code below builds the document, computes a validator and answers conditional requests. Titles and summaries are wrapped in CDATA sections, so ampersands, quotation marks and angle brackets in your content cannot break the XML. The only sequence that is illegal inside CDATA is its own terminator, and the helper splits it safely.

// src/routes/feed.xml/index.ts
import type { RequestHandler } from '@builder.io/qwik-city';
import { getPublishedPosts, type Post } from '~/lib/posts';

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

const cdata = (text: string) =>
  '<![CDATA[' + text.split(']]>').join(']]]]><![CDATA[>') + ']]>';

function buildFeed(posts: Post[]): string {
  const newest = posts.length ? posts[0].publishedAt : new Date(0);
  const items = posts
    .map((post) => {
      const url = SITE + '/blog/' + encodeURIComponent(post.slug) + '/';
      return [
        '<item>',
        '<title>' + cdata(post.title) + '</title>',
        '<link>' + url + '</link>',
        '<guid isPermaLink="true">' + url + '</guid>',
        '<pubDate>' + post.publishedAt.toUTCString() + '</pubDate>',
        '<description>' + cdata(post.summary) + '</description>',
        '</item>',
      ].join('');
    })
    .join('');

  return (
    '<?xml version="1.0" encoding="UTF-8"?>' +
    '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel>' +
    '<title>Example Journal</title>' +
    '<link>' + SITE + '/</link>' +
    '<description>News and guides from Example Journal.</description>' +
    '<language>en</language>' +
    '<lastBuildDate>' + newest.toUTCString() + '</lastBuildDate>' +
    '<atom:link href="' + SITE + '/feed.xml" rel="self" type="application/rss+xml"/>' +
    items +
    '</channel></rss>'
  );
}

async function etagFor(body: string): Promise<string> {
  const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(body));
  const hex = Array.from(new Uint8Array(digest))
    .map((byte) => byte.toString(16).padStart(2, '0'))
    .join('');
  return '"' + hex.slice(0, 32) + '"';
}

function etagMatches(header: string | null, etag: string): boolean {
  if (!header) return false;
  return header.split(',').some((token) => {
    const value = token.trim().replace(/^W[/]/, '');
    return value === '*' || value === etag;
  });
}

export const onGet: RequestHandler = async ({ request, send }) => {
  const posts = await getPublishedPosts(20);
  const body = buildFeed(posts);
  const etag = await etagFor(body);
  const headers = { ETag: etag, 'Cache-Control': 'public, max-age=300' };

  if (etagMatches(request.headers.get('If-None-Match'), etag)) {
    send(new Response(null, { status: 304, headers }));
    return;
  }

  send(
    new Response(body, {
      status: 200,
      headers: { ...headers, 'Content-Type': 'application/rss+xml; charset=utf-8' },
    }),
  );
};

Start the development server and open /feed.xml. The browser should show the XML or offer it for download, and the response should carry the right content type. The example imports the types from the package that Qwik City releases up to Qwik 1 use; if your project uses a newer package name for the router, import the request handler type from there, because the shape of the handler is the same.

Why CDATA and a manual builder

A feed library is fine, and the rss package works well in a Qwik City project, but a short builder keeps the endpoint free of dependencies and portable to edge runtimes where some Node libraries are unavailable. The risk of building XML by hand is escaping, and CDATA removes that risk for the two fields that contain free text. Links and GUIDs are built from a slug that has been through encodeURIComponent, so they contain no characters that need escaping. If you ever add query strings to a link, escape the ampersand inside the URL or move the value into CDATA as well.

How the ETag logic works

Auto-posters, readers and search engines request a feed often, and almost always nothing has changed. A validator lets them ask a cheap question: has the document changed since the version I hold? The handler hashes the finished body with the Web Crypto API, quotes the hash as an entity tag and compares it with the If-None-Match header. A match produces a 304 response with no body, which saves bandwidth for both sides and keeps your server calm. Web Crypto is available in Node and in edge runtimes, which is why the example does not import a Node module.

The hash is computed from the body, which brings one rule: the body must not change unless the content changes. That is why the last build date comes from the newest post and not from the clock. If you wrote the current time into that element, the hash would change on every request, no client would ever receive a 304 and the validator would be useless. The same applies to any value generated at request time. A compressing proxy may turn a strong tag into a weak one, which is why the comparison strips the W/ prefix.

Where each field comes from

Feed elementSourceRule
titlePost titlePlain text inside CDATA
linkPublic address of the pageAbsolute, with https, returning 200 directly
guidSame address, or a stored identifierNever changes after publication
pubDatePublication dateUTC, never the current time
descriptionShort summaryOne or two sentences of plain text
lastBuildDateNewest post dateChanges only when content changes

The identifier is the most important decision. An auto-poster remembers which items it has already shared by their GUID. If the value changes when someone edits a slug or republishes an article, the same story is shared again. If you may rename slugs, store a separate permanent identifier and write it into the guid element with isPermaLink set to false.

Caching without delaying new posts

The Cache-Control header in the example lets shared caches keep the response for five minutes, and the ETag lets everyone revalidate cheaply after that. If you place a content delivery network in front of the site, keep the lifetime short so a new post does not wait long for its turn. A feed that lags behind the website by an hour defeats the purpose of automation. Also check that your host does not serve a cached copy of an old build: a feed that is generated at build time and never rebuilt is a common reason for items that never appear. For the background, read how auto-posting tools use ETags and conditional requests এবং why auto-posts are delayed and how to fix it.

Deployment adapters and static builds

Qwik City runs on many platforms through adapters: Node servers, Cloudflare Pages, Netlify, Vercel and others. The endpoint above runs at request time on any adapter that supports server-side rendering. If you deploy a fully static build, the endpoint has to be generated at build time instead, and the feed will only change when you rebuild and redeploy. In that case, either trigger a rebuild whenever you publish or use a small build script that writes feed.xml into the output folder. Whichever route you choose, open the deployed address after the first release, because a path that works in development can behave differently on the host.

Make the feed discoverable

Add a link element to the head of your root layout so browsers, feed readers and tools can find the feed from any page: a link with rel set to alternate, type set to application/rss+xml, the title of your site and the address of the feed. With that in place, a visitor or an auto-poster that only knows your home page can locate the feed itself. The details are in the guide to feed autodiscovery.

Test the feed before you connect it

A few minutes of testing prevents days of confusion later. Check the running site from the outside:

  • Run curl -i https://example.com/feed.xml and confirm a 200 status, the right content type and an ETag header.
  • Repeat the request with the tag you received in an If-None-Match header and confirm that the answer is 304.
  • Paste the public address into the W3C Feed Validation Service and fix every error.
  • Publish a test post, wait for the cache lifetime and confirm that it appears once, at the top.
  • Change the title of an existing post and confirm that its GUID stays the same.

There is a longer checklist in the feed validation guide and a short curl routine in the guide to debugging a feed with curl.

Common mistakes to avoid

  • Current time in the body. It changes the hash on every request and disables the 304 answer.
  • Unstable GUIDs. Changing them makes auto-posters share old stories again; see why a feed auto-posts the same article twice.
  • Future posts in the feed. Always filter on the publication time.
  • Wrong content type. A feed sent as text or HTML confuses some readers; see the content type header guide.
  • Relative links. Every link in the feed must be absolute; see why relative URLs break feed links.
  • A feed behind a login or a bot challenge. An auto-poster must be able to fetch it without credentials.

How PostRSS works with a Qwik City feed

PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your feed endpoint, 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 item, 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 and posting windows let you tune each channel, 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

Qwik City needs only a route folder, a request handler and a short builder to serve a dependable RSS feed: select published posts dated in the past, wrap free text in CDATA, use a stable GUID, write every date in UTC, derive the last build date from the newest post and send the result as a Response with the right content type. Add a hash-based ETag so repeat requests end in a 304, link the feed from your layout, test it with curl and a validator, keep the address unchanged and connect it to an auto-poster. After that, every post you publish can reach your social channels automatically.

FAQ

Does Qwik City have a built-in RSS generator?

No. Qwik City has no feed support, but an endpoint in a folder named feed.xml can return any XML you build, and a small function or the rss package produces valid RSS.

Where do I put the feed file in a Qwik City project?

Create src/routes/feed.xml/index.ts and export an onGet handler. The folder name becomes the address, so the feed is served at /feed.xml.

Why does my feed never return 304?

Most often the body changes between requests, for example because the last build date is the current time. Take that date from the newest post and the hash stays the same until the content changes.

Can I generate the feed at build time instead?

Yes, for a fully static site. Write feed.xml into the output folder with a build script and rebuild whenever you publish, otherwise the feed will be out of date.

Can I use this feed with PostRSS?

Yes. PostRSS reads any valid RSS or Atom address that is reachable without a login. Paste the address, connect your channels and new items are shared as soon as they appear.

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.

আমাদের টিমের আরও টুল

PostRSS-এর পেছনের টিম Internet Solutions-এর তৈরি। প্রতিটি পণ্য নিজের মতো করে আপনার সময় বাঁচায়।

ওয়েবসাইটের জন্য AI লাইভ চ্যাট Talkmio আপনার ওয়েবসাইট আপনার নিজের কনটেন্ট থেকে, দর্শকের ভাষায়, 24/7 উত্তর দেয়। ফ্রি প্ল্যান · কার্ড লাগবে না AI সহকারী Ask Mio চ্যাট, কোড, ডিজাইন, লেখা ও গবেষণা। প্রতিটি কাজের জন্য Mio সেরা মডেলটি বেছে নেয়। ফ্রি প্ল্যান ব্লগ ও সোশ্যাল মিডিয়ার জন্য AI অটোপাইলট AI Blog Autopilot AI 2,000–3,000 শব্দের SEO আর্টিকেল লেখে এবং প্রতিটি 60 সোশ্যাল নেটওয়ার্কে শেয়ার করে। প্রথম 3টি আর্টিকেল ফ্রি ওয়েবসাইট হেলথ চেক সাইট AI অডিট SEO, গতি, SSL, নিরাপত্তা ও ইমেইল সেটআপ এক রিপোর্টে, কোনটা আগে ঠিক করতে হবে সেই ক্রমে। প্রথম অডিট ফ্রি গভীর SEO ক্রল সাইট SEO AI অডিট AI সার্চে দৃশ্যমানতাসহ 7টি ক্ষেত্রে পূর্ণ SEO ক্রল, প্রভাব অনুযায়ী সাজানো সমাধানসহ। প্রথম অডিট ফ্রি RSS ও পণ্য ফিড RSS ফিড ক্রিয়েটর যেকোনো ওয়েব পেজ থেকে RSS তৈরি করুন, সঙ্গে Google ও Meta-র জন্য পণ্য ফিড যা নিজে থেকেই আপডেট হয়। ফ্রি প্ল্যান ওয়েব ডেভেলপমেন্ট ও SEO ইন্টারনেট সলিউশনস ওয়েবসাইট, ই-শপ ও কাস্টম সিস্টেম — আমাদের টিম ডিজাইন করে, তৈরি করে ও পরিচালনা করে। 2011 থেকে