Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Feeds

demo of feeds

Feeds is a minimal RSS reader that mimics the original experience of RSS. It's just a list of posts. No categories, no marking a post read or unread, and there is no in-app reading. With this approach you have to read the post on the author's personal website and experience it in its original context.

  • Single Go binary with embedded assets
  • Local SQLite storage with a background poller (ETag / If-Modified-Since aware)
  • Password-protected admin panel for managing subscriptions and categories
  • OPML import and JSON/OPML export
  • Feed discovery from any site URL
  • JSON REST API guarded by a Bearer token
  • Ad-hoc preview by passing feed URLs as query params
  • Dark themed UI with Commit Mono font

Configure

Environment Variables

VariableDescriptionDefault
ADMIN_PASSWORDPassword for the admin panel--
API_KEYBearer token for the JSON API at /api/*--
BASE_URLPublic base URL of the apphttp://localhost:3000
HOSTBind address0.0.0.0
PORTBind port3000
DB_PATHSQLite database pathfeeds.sqlite
DEFAULT_POLL_MINUTESBackground poll interval in minutes (overridable from the admin panel)30
ITEM_CAP_PER_FEEDMaximum stored items per subscription; older items pruned200
COOKIE_SECUREEnable HTTPS-only cookiesfalse

ADMIN_PASSWORD is required to access the admin panel. API_KEY is only needed if you want to call the JSON API from outside the browser.

Deploy

Railway

The easiest way to deploy Feeds is with the one-click Railway template. See the Deploying with Railway guide for a walkthrough of the process. Feeds requires ADMIN_PASSWORD to enable the admin panel. Attach a volume at DB_PATH to persist the SQLite database.

Deploy on Railway

Docker

cd apps/feeds
cp .env.example .env
# Edit .env with your credentials
docker compose up -d

Binary

Install with Homebrew:

brew install stevedylandev/tap/feeds

Or grab a prebuilt binary from the releases page.

You can also build from source:

cd apps/feeds && go build .

The resulting binary is self-contained with all assets embedded. Copy it to your server with a configured .env file and run it directly.

Use

Admin Panel

Set ADMIN_PASSWORD and visit /admin/login. From the admin panel you can:

  • Add feeds by URL (title and site URL are auto-detected on first fetch)
  • Discover feeds from any site URL
  • Import an OPML file
  • Organize subscriptions into categories
  • Adjust the background poll interval

The poller runs automatically on launch and re-polls every DEFAULT_POLL_MINUTES (or the value saved in the admin panel). Items are deduplicated by GUID and each subscription is capped at ITEM_CAP_PER_FEED.

URL Query Param (preview mode)

You can preview any feed without subscribing by passing it via query string:

?url=https://bearblog.dev/discover/feed/

You can also preview multiple URLs at once by using commas to separate them:

?urls=https://bearblog.dev/discover/feed/,https://bearblog.stevedylan.dev/feed/

Pointing ?url= at an OPML file fetches and previews every feed it lists, up to 5 items per feed:

?url=https://example.com/subscriptions.opml

Preview mode bypasses the database and renders whatever the feed returns live.

Feeds Export

The /feeds endpoint exports your subscriptions in JSON or OPML format:

/feeds?format=json
/feeds?format=opml

JSON API

Set API_KEY to enable programmatic access. All /api/* routes accept Authorization: Bearer <API_KEY> or a valid admin session cookie.

MethodPathPurpose
GET/api/itemsList items. Query: limit, unread, category_id, subscription_id
POST/api/items/{id}/readMark item read
POST/api/items/{id}/unreadMark item unread
GET/api/subscriptionsList subscriptions
POST/api/subscriptionsAdd subscription. Body: {feed_url, title?, category_id?, category_name?}
PATCH/api/subscriptions/{id}Update subscription. Body: {category_id?, category_name?, clear_category?}
DELETE/api/subscriptions/{id}Remove subscription
GET/api/categoriesList categories
POST/api/categoriesCreate category. Body: {name}
DELETE/api/categories/{id}Remove category
POST/api/import/opmlImport OPML (multipart file field)
GET/api/settingsGet poll interval and item cap
PUT/api/settingsUpdate poll_interval_minutes (1-1440)
POST/api/discoverDiscover feeds for a site. Body: {base_url}