Self-hosted service
pietheinstrengholt/rssmonster avatar
pietheinstrengholt/rssmonster

RSSMonster: a self-hosted reader that organises feeds around stories

Modern, self-hosted RSS reader with smart folders, powerful search, and a clean three-pane reading experience. Built with Vue and Express.

570 stars52 forksJavaScriptMIT

At a glance

What is it?
RSSMonster is a Vue and Express feed reader whose interesting idea is to work above the item level, grouping reports about the same occurrence into events, ranking with explainable signals, and letting you define reusable smart folders from search expressions, with the local inference service entirely optional.
Who is it for?
RSSMonster is the right tool for a reader who has stopped being able to cope with an inbox and wants the system to group related coverage, show why something is ranked highly, and let a rule run over incoming articles. It is the wrong tool for a shared team feed that needs multi user accounts with a hosted service behind it, for a reader who wants a minimal reader with no server at all, and for anyone unwilling to run a container with a database.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A reader that treats feeds as a stream of signals

RSSMonster is described as a modern, self-hosted RSS reader that turns information overload into organized, explainable reading, with smart folders, detailed search and a three-pane reading experience, built with Vue and Express. The interesting word in the description is explainable.

The framing in the why section is that RSSMonster treats your feeds as a stream of signals rather than a pile of unread items. You keep the familiar feed inbox, and then the organisation layer decides what deserves attention and how different reports fit together. That is a different starting point from most readers, which organise by subscription and leave the judgement to you.

The audience follows. It is a person with a large subscription list and a backlog, who wants the system to do the triage. The topics attached to the repository include feed aggregator, feed reader, news feed, rss parser, and also fever-api and google-reader, which tells you that the project is conscious of the older sync APIs that existing reader clients and scripts expect to talk to.

The repository is a full stack application rather than a single service. There is a client directory, a server directory, an inference directory, a desktop directory, and a docs directory holding the feature documentation, along with a Dockerfile, a compose file, a MySQL variant of the compose file, a deploy script and an ecosystem.config.cjs for process management. The root package.json is private, uses ES modules, and has a single dev script that runs six processes at once through concurrently, which gives you a good picture of the moving parts.

Events and duplicate handling: the level above the item

The capability that distinguishes RSSMonster from a conventional reader is the semantic events layer.

The first bullet in the feature list is about following a story without rereading every headline. Semantic Events collect reporting about the same occurrence and let you expand its coverage, so an event is a grouping of items rather than an item. Duplicate handling sits alongside it and separately identifies repeated content, preserving the distinction between a syndicated copy and another publisher's reporting. That distinction is the useful part: a wire story republished by ten outlets is one piece of reporting, while ten outlets independently covering the same thing is a story, and only the second is worth expanding.

The Events view is described as a dashboard for inspecting story coverage and broader themes, and the Related reading work connects reports about an occurrence.

Ranking is where the explainable part comes in. Recommended emphasizes your personal interests, and Top Stories surfaces current coverage with broad source support. In both cases you can inspect the contributing signals, and you can choose chronological reading instead when you simply want to catch up. The Interest Islands feature is the learning half: it learns recurring personal interests from reading feedback, and it shows you the interests it has identified so you can mute the ones you do not want used for recommendations.

The stated principle underneath all of this is that the HTML tags are the source of truth and the model is only filling gaps, and the same attitude appears in the search section, where inference-backed selections are only available when the corresponding processing is enabled and available.

Smart Folders, search expressions and automated actions

Organisation in RSSMonster has three layers, and they are the parts a power user will actually live in.

The first is the ordinary structure: subscriptions arranged into categories, articles labelled with tags, and saved articles kept for later. On top of that, feed item filters accept or exclude future entries per subscription, which is a way of saying that a feed is only interesting for its podcast episodes, or only for the long form posts, and the rest should not appear at all.

The second is automated actions, which apply regular expression rules to bookmark, mark read, tag, hide, or override scores on matching incoming articles. Regular expressions over the incoming stream is a blunt and effective instrument, and the score override is the interesting one because it lets you push back on the ranking rather than accept it.

The third is the search layer and the smart folders built on it. Search combines words, dates, article state, tags, and supported score or semantic filters, and the readme gives a concrete example of a saved query, @today unread:true sort:desc. Any such query can be saved as a smart folder, and new matches appear automatically. A project watchlist, today's unread articles, and a quality-focused research inbox each get their own rules, and the articles do not have to be moved between collections to belong to more than one of them. That is the design idea in one sentence: a view is a query, not a container.

It also means the whole organisation model depends on the inference backend for the parts that use semantic or score filters, which is why the readme is careful to say those selections need the corresponding processing to be enabled and available.

Reading modes and the three-pane layout

The reading side is more elaborate than a list of links, and the documentation organises it by mode.

Reader is the default three-pane desktop layout, with navigation, an article list and the selected article, and the screenshot in the readme shows exactly that. Expanded mode reads the article content and lets you compare story sources, Summarized mode gives short previews in a compact stream, and Headlines offers a denser list. Summary bullets displays generated summaries when analysis is available, so the summary feature degrades to nothing when there is no inference rather than to something misleading.

Inside the Desktop Reader there is a focused article toolbar for read state, bookmarks and opening the original, and you can choose Small, Medium or Large text with the Aa control, with the size remembered in your browser. The headphones button reads the rendered article body using the browser's own text-to-speech when it is supported, with pause and resume on subsequent clicks. You can also expand the article to hide the middle list while keeping the sidebar visible and restore the normal layout with the same button.

The rest is the ordinary work of a reader done carefully: keyboard shortcuts, portrait bookmark swipes, light, dark or system themes, and control over when an article is marked read. There are separate responsive layouts for wide and narrow screens, and the readme shows both in dark mode, which is a small signal that the mobile experience was designed rather than inherited.

The documentation points at a reader implementation notes file for the layout, typography and interaction details, and at a usability document for the differences between the modes.

Deployment: the compose file shows every knob

The compose file is the best single view of the deployment surface, and it is unusually well commented.

yaml
name: rssmonster

services:
  rssmonster:
    image: "${RSSMONSTER_IMAGE:-rssmonster/rssmonster:${RSSMONSTER_TAG:-latest}}"
    container_name: rssmonster
    restart: unless-stopped

    ports:
      - "${RSSMONSTER_BIND_ADDRESS:-127.0.0.1}:${RSSMONSTER_PORT:-3000}:3000"

    environment:
      NODE_ENV: production
      PORT: 3000
      DB_DIALECT: sqlite
      DB_STORAGE: /app/data/rssmonster.sqlite

Several things are worth noticing. The port binding defaults to the loopback interface, so out of the box the reader is not reachable from the network, and the image and tag are both overridable so a pinned version is one environment variable away. The SQLite profile carries a comment saying it is for lightweight local experimentation, that it intentionally omits the AI worker, and that the MySQL profile is the one for database-intensive AI jobs, which is a clear statement of when to move.

The required secrets are enforced by the compose file itself, with the JWT secret and the Fever credential secret written so that the container refuses to start if they are not set, while the encryption key is optional. The remaining variables are ordinary operational settings: token lifetimes defaulting to a day and a month, a trust proxy flag, an internal host allowlist, feed limits and timeouts, the VAPID keys for web push, and the flag that turns the optional inference service on.

The proxy variables are handled with care, with the lowercase host forms taking precedence over the uppercase ones, which is the behaviour you want when a container runtime injects its own proxy configuration.

The container build and the migration that runs on start

The Dockerfile is a three stage build on node:22-alpine, and the stages map onto the parts of the application.

The first stage builds the Vue client with npm ci and npm run build. The second installs the server dependencies with npm ci --omit=dev, and it installs python3, make and g++ first, with a comment explaining why: the tooling is needed if sqlite3 has to compile a native module. That is a real constraint for anyone building the image on a platform without prebuilt binaries.

The final stage copies the server source, the production node_modules and the built client, and the comment is explicit that the built Vue client goes into the directory served by Express, so the same process serves the API and the single page application.

dockerfile
FROM --platform=$TARGETPLATFORM node:22-alpine

ENV NODE_ENV=production

WORKDIR /app/server

# Copy server source.
COPY server .

# Copy production server dependencies.
COPY --from=server-deps /build/server/node_modules ./node_modules

# Copy built Vue client into the directory served by Express.
COPY --from=client-build /build/client/dist ./dist

The runtime details are careful. A non-root user is created, two directories are made writable for the application, and a comment explains that Docker copies that ownership into newly created named volumes, which is what makes a persistent volume work on first run rather than only after a manual fix.

The last line is the one that changes the deployment story. The command runs the database migration and then starts the server, and the comment says this makes a fresh SQLite deployment self-initialising while remaining safe for existing MySQL and SQLite databases through the SequelizeMeta table. In other words, upgrading the image applies pending migrations, and a first run creates the schema.

Where RSSMonster is the wrong tool

Four limits, and the first is about the optional part of the stack.

The semantic features depend on the inference service, and the compose file is explicit that the SQLite profile omits the AI worker. The smart folders, the score filters, the semantic selections, the summaries and the event grouping all degrade when the inference backend is absent, and some of them degrade to nothing. A reader who wants the organisation features is committing to running the inference service, and the readme's own framing is that you choose how much infrastructure you need, from SQLite for lightweight personal reading up to MySQL or MariaDB with optional local inference.

The second is that this is a server application. There is no static, file-based mode, the client is served by Express, and the state lives in a database. For a reader with thirty feeds, that is an operational commitment out of all proportion to the problem, and the desktop directory and the ecosystem config file show that the intended deployment is a long lived process rather than a local file.

The third is the multi user question. The presence of a Fever credential secret and the Fever API topic indicate that the protocol is supported, but the readme's user facing description is about one person's reading, with personal interests learned from reading feedback and per browser remembered settings. The Fever API compatibility looks like a way for existing clients to talk to it rather than a claim of a hosted team service, and the documentation is not detailed enough here to promise more.

The fourth is the pace. The 2.x line has been shipping frequently, with 2.1.1, 2.2.0 and 2.3.0 published within a month of each other in the middle of 2026, and a release notes file for 2.4.0 already in the repository. A project moving that fast needs a deliberate upgrade policy, because component names in the documentation and in your configuration will change.

Licence, releases and what to check before you deploy it

The licence is MIT, with a LICENSE.md at the root of the repository, so the code can be used, modified and redistributed in commercial and self hosted deployments with the notice kept. This is not legal advice, and the feed content you fetch is a separate matter from the licence of the reader.

The release history is quick. Version 2.1.1 was published on 2026-08-10, 2.2.0 on 2026-08-11 and 2.3.0 on 2026-09-09, and the repository also contains a dedicated release notes file for 2.4.0, which tells you the line is still moving. The last push was on 2026-10-14 and the repository is not archived, so the work is current. The README also carries a Docker pulls badge, a CI badge, a licence badge and a stars badge, which is the usual set for a project of this type.

There is documentation worth reading before you deploy. The docs directory holds per feature documents, and the readme links the reading modes, the keyboard shortcuts, the feed item filters, the automated actions, the search syntax, the smart folders, the events and the interest islands pages. There is a GLOSSARY.md at the root, which is a good sign for a project with this much domain vocabulary, and a SECURITY.md alongside a contribution guide, a codecov configuration and a deploy script.

The concrete checks are short. Set the three required secrets, because the compose file will not start without two of them. Choose the SQLite or the MySQL profile deliberately rather than by accident, since the comments in the compose file make the difference explicit. Decide whether you will run the inference service, because the answer determines which half of the feature list you actually have. And pin the image tag rather than tracking latest, because the releases are frequent and the compose file is set up for exactly that.

Editorial conclusion

RSSMonster is the right tool for a reader who has stopped being able to cope with an inbox and wants the system to group related coverage, show why something is ranked highly, and let a rule run over incoming articles. It is the wrong tool for a shared team feed that needs multi user accounts with a hosted service behind it, for a reader who wants a minimal reader with no server at all, and for anyone unwilling to run a container with a database. Before adopting, set the three required secrets rather than leaving them unset, decide between the SQLite and the MySQL profile before the first import, and read the release notes, since the 2.x line has been moving quickly and the component names in the documentation will have shifted.

Frequently asked questions

What is RSSMonster?

It is a modern, self-hosted RSS reader built with Vue and Express, with smart folders, detailed search and a three-pane reading experience. Its distinguishing idea is to organise feeds as a stream of signals rather than a pile of unread items, using semantic events to group reporting about the same occurrence.

How do I deploy RSSMonster with Docker?

The compose file defines a single service from the rssmonster/rssmonster image, binding to 127.0.0.1 on port 3000 by default and running in production mode with SQLite by default. The JWT secret and the Fever credential secret are required and the container refuses to start without them, and a separate MySQL compose file is provided for heavier workloads.

Do I need the inference service to use RSSMonster?

Not to run it, but yes for much of the organisation layer. The compose file notes that the SQLite profile intentionally omits the AI worker, and the documentation says inference-backed score and semantic selections need the corresponding processing to be enabled and available, so the smart folders and semantic features depend on it.

What are Smart Folders in RSSMonster?

They are reusable selections defined by search expressions rather than by moving articles between collections. Search combines words, dates, article state, tags and supported score or semantic filters, and a query such as @today unread:true sort:desc can be saved as a smart folder whose new matches appear automatically.

Official sources

  1. License: MIT
  2. pietheinstrengholt/rssmonster on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pietheinstrengholt-rssmonster.svg)](https://hysenlabs.com/projects/pietheinstrengholt-rssmonster)

Was this useful?