Background

I have been using feedly for years to read rss feeds. It is a great service however it grows more and more complicated and tries hard to sell me their premium features. I understand that they need to make money, but I decided to find a self-host solution for my simplest need: read self selected rss feeds on a clean UI. no AI recommendation, no social sharing, no fancy features. Just a simple rss reader. Then I found this miniflux. It is a very simple as they claimed they are minimalist. Yet they have all the essential features of an rss reader. The best part, It is open sourced and offers docker images for you to deploy freely, they do have a 15$/year paid hosted plan which I think is fair. I deployed one on my private k8s and it works like a charm. I then walked through the code and found it is even more enjoyable to read. I would like to share my using experience and findings here.

Features overview

miniflux-demo

The essential features I need are:

  • Add rss feeds
  • Read new feeds
  • Mark as read
  • Mark as starred
  • Read history feeds
  • Search

Miniflux has all of them as well as surprising features like filter with regex pattern. This is so helpful when I need to distill the feeds according to the selected keywords or topic. I also like the minimalist UI design just like my own blog style itself:)

How I hosted it

I have a private k8s cluster running on my home server. So to deploy miniflux it is simply finding out its official docker image, all its dependencies– a postgres database. Then wrap them in a deployment file and ship it to the cluster. Here is an example of docker-compose file found from official repo which you can tweak to fit your own need.

https://github.com/miniflux/v2/blob/main/contrib/docker-compose/basic.yml

I have in my previous post talked about how to deploy a k8s cluster on a single machine. You can refer to this one if you are interested.

The site speed is impressive as it is purely written in go and some clean html and js. I have more than 100 feeds and it takes couple of seconds to fetch and fitler the content. I did expeirence some timeout issue when I tried to add a very large feed list like arxiv. To be fair it not common case and my server runs on a 8 years old thinkpad whose cpu might be the bottleneck.

How it works

Since I’m impressed with its performance and simplicity I decided to dig into the code and see how it works.

The first thing I did is to map out its data model using dbeavr. Here is what it looks like miniflux_data

It is quite straightforwrd that feeds, entries, users are the core models. It looks simple but if you dig into it you will find some clues of how it refeshes the feeds using “next_check_at”, how to ensure the uniqueness of each entry using ‘hash’ and how it handles multiple users by record their entry reading status and so on.

Then if you go to the codebase and starting from Makefile you will find the entry point which is main.go. It sits in the root folder of the project.

package main // import "miniflux.app/v2"

import (
	"miniflux.app/v2/internal/cli"
)

func main() {
	cli.Parse()
}

It is a very common pattern in go to use cli package to parse the command line arguments. Then you can follow the code to see how the cli.Parse() works.

In cli.go it parses the parameters, set up the database connections then starts a Daemon method which is the core of this application to run the background tasks of fetching the feeds

Here daemon.go it does the following things:

  1. Initialize the worker pool
  2. Start two schedulers, one for fetching feeds and one for cleaning up the database
  3. Start the http server to serve the APIs for the frontend
  4. Sending notification if it is configured

Cli->daemon->Worker is what I think the trunk of the codebase. Of course there are numerous details like how to set up the models, how the worker is implemented and how the feedHandler work to process the entries of the feeds, which you can follow the references to find out.

Some thoughts

I would say the architecture is clean and straightforward. You may complain it has very few comments in the code but if you organize the code in a clean way you don’t need to comment too much. I feel like I’m reading a well structured novel when I read it through. I just wish all open source projects are written like this.

While I have a nice experience with miniflux both on its feature and code implementation I do think it can do even better , e.g. the filtering rules for the feeds are too simple and not easy to use. You need to konw how to write regex and based on my experience it can only filter by the title. same situation applies to the blocking rules. Another thing is the search function might not support large amound of feeds due to the limitation of the database. Yes it’s not hard to pipe the data to a search engine but it might object to the minimalist principle of the project.