Twine RSS Reader: a Kotlin and Compose Multiplatform client for Android, iOS and desktop
Twine: A multiplatform RSS reader built using Kotlin and Compose
At a glance
- What is it?
- Twine is a cross-platform RSS reader built with Kotlin Multiplatform and Compose Multiplatform, distributed through app stores and IzzyOnDroid. It covers feed management, reader view and optional sync through FreshRSS, Miniflux or Dropbox, under GPL-3.0.
- Who is it for?
- Adopt Twine if you want one RSS client across Android, iOS and desktop and you are willing to sync through FreshRSS or Miniflux rather than a hosted service of its own. Do not adopt it if you need a web client, a server, or a sync backend that is not marked alpha.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Twine solves for people who read feeds on more than one device
Most RSS clients are single-platform. A reader that works well on Android is usually a separate project from the one on iOS, and desktop is a third codebase or nothing at all. Twine's answer is Kotlin Multiplatform with Compose Multiplatform: one shared UI and presentation layer, plus thin platform entry points. The README describes the structure directly, with `androidApp` and `iosApp` holding platform-specific code and `shared` holding the core UI logic, ViewModels built with `kotlin-inject`, and shared presentation logic.
The target user is someone who already self-hosts a feed backend or wants to. Twine lists cloud sync support for FreshRSS (GReader), Miniflux and Dropbox, and the Dropbox entry carries an alpha marker in the feature list. That ordering matters. Twine is not a hosted service with an account you create on the project's site. It is a client that expects you to bring a server or a storage provider. If you have no FreshRSS or Miniflux instance and no interest in running one, the sync story is thinner than the feature list first suggests.
The feature set is what you would expect from a mature reader: feed management with add, edit, delete, pin and group; a bottom bar for pinned feeds and groups; bookmarks; post search; blocked words for filtering; background sync; home screen widgets; OPML import and export; and light, dark and amoled themes. Feed formats covered are RDF, RSS, Atom and JSON. Twine also tries to discover feeds when you give it a website homepage, which is the step that usually stops people from adding a feed at all.
How the Kotlin Multiplatform layers fit together
The repository layout is the clearest description of the architecture. Under `core/` sit `base` for common interfaces and platform abstractions, `data` for repositories, the local database and sync logic, `model` for domain models, and `network` for fetching and parsing feeds. The shared module depends on those. The platform apps are entry points rather than places where logic lives.
The data layer uses SQLDelight for the local database and Ktor for networking, both listed in the tech stack. That combination is the standard Kotlin Multiplatform pairing, and it means the same persistence and fetch code runs on every target. Coil handles images, and the multiplatform markdown renderer handles article content in the reader view. Dependency injection is `kotlin-inject`, which is a compile-time DI library rather than a runtime one.
The practical consequence is that a change to feed parsing or sync logic lands once and applies everywhere. The cost is that anything genuinely platform-specific, widgets on Android for example, cannot be shared. The README lists home screen widgets as a feature without qualifying the platform, and the presence of a separate `androidApp` module is the reason to check that yourself before assuming parity across iOS and desktop. The README does not document a per-platform feature matrix.
There is a `desktopApp` directory in the repository root even though the README's project structure section does not mention it. The README describes `androidApp`, `iosApp` and `shared` only. That is a real gap in the documentation, and anyone planning to use the desktop build should read the build files rather than the README to see what it targets.
Building Twine from source and importing your first feeds
The README states that you can clone the repo and build it locally without requiring any changes, and that the project requires JDK 21 or newer. Which Android Studio version you need depends on the AGP version defined in `gradle/libs.versions.toml`, so read that file before importing.
Start with the clone and a first build. The Gradle wrapper is checked in, so no separate Gradle install is needed.
git clone https://github.com/msasikanth/twine.git
cd twine
./gradlew buildThe README does not document a run task or a target name for the desktop application, so the build above is the step the documentation actually supports. On Windows use `gradlew.bat` instead of `./gradlew`.
If you plan to contribute rather than just build, the project uses ktfmt through the spotless Gradle plugin and the bundled IntelliJ codestyle. The README gives one command for that, and it should be run before opening a pull request.
./gradlew spotlessApplyFor normal use you do not build anything. The README points to Google Play, the App Store and IzzyOnDroid, with the Android package id `dev.sasikanth.rss.reader`. Install from one of those, then add a feed. The README states that Twine looks for feeds when given any website homepage, so pasting a site URL rather than a feed URL is the intended first move. OPML import is the faster path if you are migrating from another reader. The README does not document the import flow step by step, so treat the in-app screens as the source of truth there.
Contributions follow a narrow rule in the README: bug fixes via pull requests, anything else starts as an issue. Translations go through Crowdin rather than pull requests.
Where Twine is the wrong tool
Twine is a client, not a service. If you want a reader that also stores your feeds on its own servers and gives you a web interface from any browser, this is not that project. The sync options are FreshRSS, Miniflux and Dropbox, and the Dropbox path is marked alpha in the README. Alpha here means you should not treat it as the primary copy of your reading state.
Platform coverage is the second boundary. The README's structure section names Android and iOS modules and a shared module. There is a `desktopApp` directory in the repository, but the README does not describe it, does not list desktop among the download options, and does not state which desktop platforms it targets. Anyone who needs a working Linux desktop reader should verify that from the build configuration instead of the README.
The third boundary is the licence. Twine is GPL-3.0. If you want to embed its feed parsing or sync code in a closed-source product, the GPL is a constraint you have to reason about, and the README offers no alternative licensing path. For personal use this is irrelevant. For a commercial integration it is the first thing to check.
Finally, the README lists no server-side component, no API for third-party clients, and no command-line interface. Automation around your feeds is not something Twine provides.
Twine against a self-hosted web reader
The natural comparison is Miniflux or FreshRSS used through their own web interfaces. Those are servers first. You run them, they store the feeds, and the browser is the client. Twine inverts that: it is a native app that talks to those servers through the GReader or Miniflux APIs.
The difference shows up in what you get for free. A self-hosted web reader works from any device with a browser, including a borrowed laptop, with no install. Twine gives you a native reading experience instead: reader view with configurable fonts and colors, dynamic theming that shifts the app's ambient color based on content, an audio player for podcasts and HTML audio tags, blocked words, and home screen widgets. Those are things a browser tab does not do well.
The trade-off is operational. With a web reader you maintain one server and every client is a browser. With Twine you maintain the server and install an app on each device, and you depend on the app's sync implementation staying correct against the server's API. Twine's advantage is that it can also run without any server at all, using local storage and OPML import and export, which a server-first reader cannot do. That makes Twine a reasonable choice for someone who wants local feeds on a phone and optional sync later, and a poor choice for someone who wants a single URL that works everywhere.
Maintenance, releases and what GPL-3.0 means here
The repository is not archived, and the last push was on 2026-09-25. Releases are frequent: v3.7.0 on 2026-08-20, v3.8.0 on 2026-08-30, and v3.9.0 on 2026-09-09. That cadence suggests the project is still moving, though the README does not publish a support policy, a deprecation policy, or a minimum supported OS version for either mobile platform.
Upgrade cost for users is low because distribution is through app stores and IzzyOnDroid, so updates arrive the normal way. The cost that matters is on the build side. The README ties the required Android Studio version to the AGP version in `gradle/libs.versions.toml`, which means the toolchain expectation moves whenever that file changes. Pinning your local toolchain to whatever the file says at the commit you build is the only reliable approach, and the README does not offer a compatibility table.
GPL-3.0 applies to the whole project. If you fork Twine and distribute a modified build, the licence terms follow that distribution. If you only run it for yourself, the obligations are minimal. If you are evaluating Twine as a component inside another product, the licence is the deciding factor and this is not a legal opinion, just a pointer to read `LICENSE.txt` in the repository root. The README lists no commercial or dual-licensing option.
Error reporting goes through Bugsnag according to the README, and the privacy policy is linked from the README rather than reproduced in it. If telemetry matters to you, read that policy before installing.
Editorial conclusion
Adopt Twine if you want one RSS client across Android, iOS and desktop and you are willing to sync through FreshRSS or Miniflux rather than a hosted service of its own. Do not adopt it if you need a web client, a server, or a sync backend that is not marked alpha. Verify first that your feeds parse as RDF, RSS, Atom or JSON, and check whether the Dropbox sync path marked alpha is acceptable for your data.
Frequently asked questions
What is Twine?
Twine is a cross-platform RSS reader built with Kotlin and Compose Multiplatform. It supports RDF, RSS, Atom and JSON feeds, and is distributed through Google Play, the App Store and IzzyOnDroid.
How do I use Twine to read feeds?
Install it from one of the stores listed in the README, then add a feed. The README states that Twine looks for feeds when given any website homepage, so pasting a site URL is the intended starting point, and OPML import covers migration from another reader.
How do I install Twine?
The README points to Google Play, the App Store and IzzyOnDroid for the Android package dev.sasikanth.rss.reader. Building from source requires cloning the repository and running the Gradle wrapper with JDK 21 or newer.
Official sources
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.
[](https://hysenlabs.com/projects/msasikanth-twine)