FreshRSS vs Tiny Tiny RSS: Which RSS Reader?

Quick Verdict

FreshRSS is the better choice for most people. It deploys as a single container with SQLite (or two with PostgreSQL), supports the Google Reader API out of the box for seamless mobile app integration, and has a welcoming community that actually helps newcomers. Tiny Tiny RSS has more powerful server-side filtering and a mature plugin ecosystem, but its four-container setup is more complex, and third-party mobile app support requires plugin workarounds.

Pick TT-RSS only if you need advanced filter rules with regex and scoring, or prefer its keyboard-driven workflow. For everyone else, FreshRSS gets you reading feeds faster with less friction.

Feature Comparison

FeatureFreshRSSTiny Tiny RSS
LanguagePHPPHP
Database optionsPostgreSQL, MySQL/MariaDB, SQLitePostgreSQL only
Multi-userYesYes
Google Reader APIBuilt-inNot available
Fever APIBuilt-inVia plugin
Extensions/plugins~20 community extensions30+ mature plugins
ThemesMultiple built-in + custom CSSMultiple built-in + custom themes
Server-side filtersBasic (labels, tags, mark read)Advanced (regex, scoring, multi-action)
Full-text fetchXPath-based scrapingVia af_readability plugin
WebSub (instant push)YesNo
Feed deduplicationBasicAdvanced (perceptual hashing)
Keyboard shortcutsYesYes (extensive, Vim-style)
Docker containers needed1-2 (app + optional DB)4 (app + updater + nginx + DB)
Official mobile appNo (uses third-party via API)Yes (Android only)
LicenseAGPL-3.0GPL-3.0

Docker Setup

Both apps run well in Docker. Here are production-ready configurations for each.

FreshRSS with PostgreSQL

Create a docker-compose.yml:

services:
  freshrss:
    image: freshrss/freshrss:1.28.1
    container_name: freshrss
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      # Timezone for feed refresh scheduling
      TZ: "UTC"
      # Feed refresh runs at these minutes past the hour
      CRON_MIN: "2,32"
    volumes:
      # Application data (settings, user data, cache)
      - freshrss-data:/var/www/FreshRSS/data
      # Third-party extensions
      - freshrss-extensions:/var/www/FreshRSS/extensions
    logging:
      options:
        max-size: "10m"
    networks:
      - freshrss

  db:
    image: postgres:16-alpine
    container_name: freshrss-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: freshrss
      POSTGRES_USER: freshrss
      # CHANGE THIS before first run
      POSTGRES_PASSWORD: change-me-to-a-strong-password
    volumes:
      # Persistent database storage
      - freshrss-db:/var/lib/postgresql/data
    logging:
      options:
        max-size: "10m"
    networks:
      - freshrss

volumes:
  freshrss-data:
  freshrss-extensions:
  freshrss-db:

networks:
  freshrss:

Start it:

docker compose up -d

Open http://your-server:8080 and the web setup wizard walks you through database connection and admin account creation. Select PostgreSQL, enter db as the host, and use the credentials from your Compose file.

FreshRSS also supports SQLite — remove the db service entirely and select SQLite during the setup wizard. One container, zero database management.

Tiny Tiny RSS with PostgreSQL

TT-RSS requires PostgreSQL and runs as four containers: the PHP-FPM application server, an Nginx web frontend, a feed updater daemon, and the database.

Create a .env file:

# CHANGE these before first run
TTRSS_DB_USER=postgres
TTRSS_DB_NAME=ttrss
TTRSS_DB_PASS=change-me-to-a-strong-password
# Must match the exact URL you access TT-RSS at
TTRSS_SELF_URL_PATH=http://your-server:8280/tt-rss
# Admin password (reapplied on every container start)
ADMIN_USER_PASS=change-me-admin-password
# Port binding (localhost only -- put behind a reverse proxy for public access)
HTTP_PORT=127.0.0.1:8280

Create a docker-compose.yml:

services:
  db:
    image: postgres:15-alpine
    container_name: ttrss-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${TTRSS_DB_USER}
      POSTGRES_PASSWORD: ${TTRSS_DB_PASS}
      POSTGRES_DB: ${TTRSS_DB_NAME}
    volumes:
      # Persistent database storage
      - ttrss-db:/var/lib/postgresql/data
    networks:
      - ttrss

  app:
    # TT-RSS rolling release — no versioned Docker tags published
    image: cthulhoo/ttrss-fpm-pgsql-static:latest
    container_name: ttrss-app
    restart: unless-stopped
    depends_on:
      - db
    environment:
      TTRSS_DB_HOST: db
      TTRSS_DB_NAME: ${TTRSS_DB_NAME}
      TTRSS_DB_USER: ${TTRSS_DB_USER}
      TTRSS_DB_PASS: ${TTRSS_DB_PASS}
      TTRSS_DB_PORT: "5432"
      TTRSS_SELF_URL_PATH: ${TTRSS_SELF_URL_PATH}
      ADMIN_USER_PASS: ${ADMIN_USER_PASS}
    volumes:
      # Shared application files (used by app, updater, and nginx)
      - ttrss-app:/var/www/html
    networks:
      - ttrss

  updater:
    # Same rolling-release image as app
    image: cthulhoo/ttrss-fpm-pgsql-static:latest
    container_name: ttrss-updater
    restart: unless-stopped
    depends_on:
      - app
    environment:
      TTRSS_DB_HOST: db
      TTRSS_DB_NAME: ${TTRSS_DB_NAME}
      TTRSS_DB_USER: ${TTRSS_DB_USER}
      TTRSS_DB_PASS: ${TTRSS_DB_PASS}
      TTRSS_DB_PORT: "5432"
      TTRSS_SELF_URL_PATH: ${TTRSS_SELF_URL_PATH}
    volumes:
      - ttrss-app:/var/www/html
    # Runs the feed update daemon instead of PHP-FPM
    command: /opt/tt-rss/updater.sh
    networks:
      - ttrss

  web-nginx:
    # Rolling release — :latest only
    image: cthulhoo/ttrss-web-nginx:latest
    container_name: ttrss-web
    restart: unless-stopped
    depends_on:
      - app
    ports:
      - "${HTTP_PORT}:80"
    volumes:
      # Read-only access to serve static files
      - ttrss-app:/var/www/html:ro
    networks:
      - ttrss

volumes:
  ttrss-db:
  ttrss-app:

networks:
  ttrss:

Note on image pinning: TT-RSS uses a rolling release model and does not publish versioned Docker tags. The official cthulhoo/ttrss-fpm-pgsql-static image only offers latest. If you want date-pinned builds, use the community Awesome TTRSS image (wangqiru/ttrss:latest-2025-02-03) instead, which follows a latest-YYYY-MM-DD tagging scheme.

Start it:

docker compose up -d

Open http://your-server:8280/tt-rss and log in with admin and the password you set in ADMIN_USER_PASS. The TTRSS_SELF_URL_PATH must match the exact URL in your browser address bar — a mismatch causes redirect loops.

The contrast is stark: FreshRSS is two containers with a setup wizard. TT-RSS is four containers with manual environment variable configuration and a critical URL-matching requirement.

API Support and Mobile Apps

This is the single biggest differentiator between the two.

FreshRSS implements the Google Reader API natively. This unlocks the best third-party RSS apps on every platform:

  • Reeder (iOS/macOS) — widely considered the premium RSS reading experience
  • NetNewsWire (iOS/macOS) — free, open source, polished
  • FeedMe (Android) — feature-rich with offline support
  • ReadYou (Android) — Material You design, clean and modern
  • Newsboat (terminal) — for reading feeds from the command line
  • Any other app supporting the Google Reader protocol (there are dozens)

FreshRSS also supports the Fever API as a second option for apps that prefer that protocol.

TT-RSS takes a different approach. It has its own official Android app (no iOS equivalent). For third-party app support, you must install the fever plugin to expose a Fever API endpoint. The Google Reader API is not available at all. The official Android app was pulled from Google Play at one point over a policy disagreement and is now distributed through the TT-RSS website directly.

If you use iOS, the choice is already made — FreshRSS is the only option with native app support. On Android, FreshRSS still wins on app variety unless you specifically prefer TT-RSS’s official client.

UI Philosophy

FreshRSS presents a familiar three-panel layout: folders on the left, article list in the center, reading pane on the right. It looks and feels like Google Reader did. The web UI is responsive and works acceptably on phone and tablet browsers even without a dedicated app.

TT-RSS defaults to a similar layout but feels denser. More toolbar buttons, more configuration dialogs, more exposed options. The keyboard shortcut system is extensive and Vim-inspired — power users who live in their RSS reader all day will appreciate the speed. The interface is desktop-focused and does not adapt well to small screens.

Plugin Ecosystem

Both support plugins, but the implementations differ significantly.

TT-RSS plugins can modify the article rendering pipeline, add API endpoints, integrate with external services, and fundamentally alter application behavior. Key plugins include af_readability (full-text article fetch), fever (Fever API for third-party apps), note (article annotations), and af_comics (webcomic support). The plugin API is mature and well-documented. This is TT-RSS’s strongest advantage.

FreshRSS extensions are simpler in scope. They add XPath scraping rules, modify CSS, or integrate with specific services. The extension API is less powerful but extensions are easier to write and less likely to break across updates. The extension repository has around 20 community-maintained options.

Filter Power

TT-RSS’s server-side filtering is genuinely more capable:

  • Regex matching on title, content, author, and link fields
  • Score-based ranking — assign positive or negative scores to articles and sort by relevance
  • Multi-action rules — a single filter can mark as read, star, assign a label, and publish an article simultaneously
  • Per-feed filter scope — apply different rules to different feeds
  • Inverse matching — trigger on articles that do NOT match a pattern

FreshRSS filters are functional but basic: match on title or content, then assign a label or mark as read. Adequate for “hide articles about topic X” rules, but not sophisticated enough for automated triage of high-volume feeds.

If you subscribe to 50 feeds and skim headlines, FreshRSS filters are plenty. If you subscribe to 500 feeds and need automated processing to surface the 10 articles worth reading, TT-RSS’s filter engine is the tool you want.

Performance

MetricFreshRSSTiny Tiny RSS
RAM idle (100 feeds)~80 MB~120 MB
RAM idle (500 feeds)~150 MB~200 MB
Feed refresh (100 feeds)~2 min (cron)~3 min (daemon)
Disk (application only)~50 MB~80 MB (across containers)
Startup timeSeconds10-20 sec (4 containers)
Minimum recommended RAM512 MB1 GB

FreshRSS is lighter because it can run as a single container with SQLite. TT-RSS always requires four containers and PostgreSQL. Both handle thousands of feeds on modest hardware, but FreshRSS is the better pick for a Raspberry Pi or a cheap VPS.

FreshRSS updates feeds via cron (CRON_MIN sets the schedule). TT-RSS runs a dedicated updater daemon that polls feeds continuously. The daemon approach means TT-RSS can deliver new articles slightly faster, but the cron approach is simpler and perfectly adequate for refresh intervals of 15-30 minutes.

Community and Development

FreshRSS is developed on GitHub with 10,000+ stars and an active contributor base. Issues get responses within days. Pull requests are reviewed constructively. Releases follow a regular schedule with clear changelogs — the latest stable is v1.28.1 (January 2025). The maintainers actively welcome new contributors.

TT-RSS has a complicated history. The original developer (fox) was notoriously hostile to feature requests and frequently combative in the forums — banning users for asking questions he considered obvious, closing issues with dismissive one-liners, and expressing strong opinions about how people should use his software. Fox eventually shut down the project’s infrastructure, and development continues under a community fork. The rolling release model (no version numbers, just the main branch) makes reproducible deployments harder and changelogs non-existent.

The software quality of TT-RSS is not in question — it works well. But when you hit a configuration issue at 2 AM, the community you turn to for help matters.

Use Cases

Choose FreshRSS If…

  • You want the fastest path from zero to reading feeds
  • You use iOS and want native app integration (NetNewsWire, Reeder)
  • You prefer a single-container SQLite deployment for simplicity
  • You value a welcoming community and predictable releases
  • You run on limited hardware (Raspberry Pi, low-end VPS)
  • You want WebSub support for instant updates from compatible feeds
  • You are migrating from Feedly, Inoreader, or Google Reader

Choose Tiny Tiny RSS If…

  • You need advanced server-side filters with regex and scoring
  • You want the mature plugin ecosystem for deep customization
  • You primarily read in the web interface with keyboard shortcuts
  • You need perceptual hashing for feed deduplication
  • You want a continuous updater daemon instead of cron-based refresh
  • You already know TT-RSS and are comfortable with its architecture

Final Verdict

FreshRSS wins for most self-hosters. It is simpler to deploy (one or two containers vs. four), has dramatically better mobile app support through its native Google Reader API, runs lighter on resources, and has a community that treats newcomers with respect. The web UI works on mobile browsers even without a dedicated app.

TT-RSS is the power tool in this comparison. Its filters and plugin system are genuinely more capable. But that power comes at the cost of a harder setup, a more complex multi-container architecture, no Google Reader API, limited mobile options, and a community that historically drove people away.

Unless you have a specific need that only TT-RSS’s filter engine or plugin system can solve, start with FreshRSS. You will be reading feeds in minutes instead of debugging a four-container stack.

For an even lighter alternative, check out Miniflux — a single Go binary that uses a fraction of the resources of either PHP-based reader.

Comments