
Short answer: To serve an RSS feed from Quarkus, add a REST resource at /feed.xml, load the newest published entries with a Panache query, build the feed with the ROME library so every value is escaped and every date is formatted correctly, and return it with the content type application/rss+xml and a short cache header. Package the service, put a reverse proxy in front, test the feed with curl and a validator, and then give its public address to an auto-poster so every new item reaches your social channels.
Quarkus is a Java framework built for fast start-up and low memory use, and many teams choose it for services that run in containers. Sooner or later such a service publishes something that people want to follow: news, product updates, job listings, event dates or release notes. The data lives in a database and is shown through an API or a front end, but nothing outside can subscribe to it. A feed fixes that without an account or an API key. This guide builds a complete Quarkus RSS feed, explains each decision and ends with the checks that keep it dependable.
A feed is worth adding whenever your service publishes things that people want to follow:
Without a feed, every announcement has to be copied to social networks by hand. If your content lives in a blog or a CMS instead, use the feed it already provides; see how to find your WordPress feed link. For the same job in another Java framework, see the Spring Boot guide.
Create a Quarkus application with REST support, Panache for database access and a JDBC driver. The example uses PostgreSQL; replace it with the driver for your own database.
quarkus create app org.acme:feed-service \
--extension=rest,hibernate-orm-panache,jdbc-postgresql
cd feed-serviceThen add the ROME library to the dependencies in pom.xml. Check the current release before you copy the version number.
<dependency>
<groupId>com.rometools</groupId>
<artifactId>rome</artifactId>
<version>2.1.0</version>
</dependency>Configure the database and the public address of the site in application.properties. Keep credentials in environment variables and never in the file itself.
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/site
quarkus.datasource.username=${DB_USER}
quarkus.datasource.password=${DB_PASSWORD}
quarkus.hibernate-orm.database.generation=none
site.url=https://www.example.comThe entity maps the table that holds your content. It uses Panache, so the query in the resource stays short.
package org.acme.feed;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.Entity;
import java.time.Instant;
@Entity
public class Post extends PanacheEntity {
public String title;
public String slug;
public String summary;
public String status;
public Instant publishedAt;
}package org.acme.feed;
import com.rometools.rome.feed.synd.*;
import com.rometools.rome.io.FeedException;
import com.rometools.rome.io.SyndFeedOutput;
import io.quarkus.panache.common.Sort;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@Path("/feed.xml")
public class FeedResource {
@ConfigProperty(name = "site.url")
String siteUrl;
@GET
@Produces("application/rss+xml; charset=UTF-8")
public Response feed() throws FeedException {
List<Post> posts = Post.find(
"status = ?1 and publishedAt <= ?2",
Sort.descending("publishedAt"),
"PUBLISHED", Instant.now())
.page(0, 20).list();
SyndFeed feed = new SyndFeedImpl();
feed.setFeedType("rss_2.0");
feed.setTitle("Example News");
feed.setLink(siteUrl + "/news/");
feed.setDescription("Latest news from Example");
feed.setLanguage("en");
if (!posts.isEmpty()) {
feed.setPublishedDate(Date.from(posts.get(0).publishedAt));
}
List<SyndEntry> entries = new ArrayList<>();
for (Post p : posts) {
SyndEntry entry = new SyndEntryImpl();
entry.setTitle(p.title);
entry.setLink(siteUrl + "/news/" + p.slug + "/");
entry.setUri("post-" + p.id);
entry.setPublishedDate(Date.from(p.publishedAt));
SyndContent description = new SyndContentImpl();
description.setType("text/plain");
description.setValue(p.summary);
entry.setDescription(description);
entries.add(entry);
}
feed.setEntries(entries);
String xml = new SyndFeedOutput().outputString(feed);
return Response.ok(xml)
.header("Cache-Control", "public, max-age=300")
.build();
}
}Several details carry most of the correctness. The query filters on both the status and the date, so drafts and items dated in the future never appear. ROME builds the document through an XML model, so an ampersand or an angle bracket in a title is escaped for you and cannot break the file. It also writes dates in the English RFC 822 form that the RSS specification asks for. The entry identifier becomes the GUID, and it comes from the database key and not from the slug, so renaming a post does not make it look new. The page size of twenty keeps the file small.
| RSS element | Source in the service | Rule |
|---|---|---|
| title | post title | Escaped by ROME, under about 100 characters |
| link | configured site address plus slug | Always absolute and always the public address |
| guid | database identifier | Never changes, even if the slug changes |
| pubDate | publication instant | Never in the future |
| description | summary | Plain text; the first sentences matter most |
The GUID deserves special attention. A new GUID makes an old item look new, and an auto-poster may share it again; see why your RSS feed auto-posts the same article twice. If your summaries contain HTML, either send them as plain text as shown or choose the HTML content type and read CDATA and HTML in RSS descriptions first.
You could write the XML by hand with a string builder, but the library removes a whole class of mistakes. It escapes values, formats dates consistently and can write several formats from the same model. Changing the feed type from rss_2.0 to atom_1.0 produces an Atom feed with the same entries, which is handy if another consumer prefers it; the differences are explained in Atom versus RSS for auto-posting. ROME is also what most Java examples use, so your colleagues will recognise it. Keep the feed type fixed for the public address, so that the address always returns the same format.
Auto-posters build the preview card from the image of the item, so add one when you can. ROME lets you attach an enclosure to an entry with the address, the size and the real type of the file. Store the full public address of the picture with the post and always use absolute addresses, because a relative one breaks when the feed is read elsewhere; see relative URLs in RSS feeds. The way these tags are handled is explained in RSS enclosure tags explained. Also make sure each article page carries correct Open Graph tags, because many networks use them for the card.
A feed is requested often, mostly by robots. Each request here runs one small query, so the cost is low, but a short cache is a sensible protection. The header in the example lets a proxy or a content delivery network serve the same copy for 300 seconds. Do not cache for hours: a long lifetime delays every share by the same amount, as explained in RSS feed caching explained. For repeat requests you can also support conditional answers. The JAX-RS API lets a resource compare an entity tag with the one sent by the client and return 304 when nothing has changed; see RSS feed ETags and conditional GET for the idea. Keep an index on the status and published columns so the query stays fast as the table grows.
The site address is the one setting that must differ between environments. Quarkus profiles let you keep a local value for development and the real one for production, for example by prefixing the property with the dev profile name and pointing it at localhost. In production, supply the public address through an environment variable so that a container image never contains a test address by accident. Check the links in the feed after every deployment: a feed that points to a staging host will be shared with those links, and fixing that afterwards means editing public posts. A one-line check with curl and grep for the host name takes seconds and prevents the problem.
Build the application and run it as a normal Java process or in a container:
./mvnw package
java -jar target/quarkus-app/quarkus-run.jarRun it under a service manager or an orchestrator so that it restarts after a crash, and put a reverse proxy such as Nginx or Caddy in front of it. The proxy terminates the secure connection, forwards the path /feed.xml and can compress the answer; see RSS feed compression. Build links from the configured site address and not from the request, because behind a proxy the host of the request can be an internal name. If you build a native executable, test the feed again before you rely on it, because libraries that use reflection can need extra configuration.
curl -i https://www.example.com/feed.xml and check for a 200 status, the XML content type and the cache header. The method is explained in debugging an RSS feed with curl.If anything looks wrong later, the checklist in RSS feed not updating helps you find the cause quickly.
PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your feed.xml resource, 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.
Quarkus serves a dependable RSS feed with one resource: query only published items dated in the past, build the document with ROME so every value is escaped and every date is correct, use a stable GUID, build links from a configured site address and return the XML with the right content type and a short cache. Package the service, put a proxy in front, test with curl and a validator, keep the address unchanged and connect it to an auto-poster. After that, every item you publish can reach your social channels automatically.
No. Quarkus provides REST, data access and configuration, and a feed is just an XML response. The ROME library is the usual choice for building it safely.
String templates break when a title contains an ampersand or another special character. ROME writes a valid document every time, formats the dates correctly and can produce RSS or Atom from the same data.
Yes. The feed only needs a list of published items with a title, a link, an identifier, a date and a summary. Use plain JDBC, a repository class or another mapper, and keep the same rules for status, date and limit.
Between ten and twenty of the newest published items is enough. An auto-poster only needs recent items, and a smaller file is faster to download and parse.
Give every item a stable identifier and use it as the GUID. Avoid editing the publication date of items that are already public, because some tools treat a changed date as a new item.
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.
What changed in the networks, what broke, and how to fix it before it costs you reach.
PostRSS-এর পেছনের টিম Internet Solutions-এর তৈরি। প্রতিটি পণ্য নিজের মতো করে আপনার সময় বাঁচায়।