Current is a self-hosted RSS feed reader backend that implements the Fever API protocol. Built with plain JavaScript (ES modules, no runtime dependencies), it runs on Cloudflare Workers with D1 as the database and KV as the cache layer.
Use it as the server-side sync engine for any Fever-compatible RSS client — Reeder, fluent-reader and more.
- Features
- Architecture
- Prerequisites
- Deployment
- Configuration
- Usage — Connecting RSS Clients
- API Reference
- Tech Stack
- License
- Fever API v3 — full read/sync protocol implementation: groups, feeds, items, read/unread/saved state
- Feed format support — parses RSS 2.0, Atom, and JSON Feed subscriptions with a built-in zero-dependency parser
- Concurrent feed fetching — fetch multiple feeds in parallel with configurable concurrency
- Cron-based auto-sync — periodic feed refreshing via Workers Cron Triggers (default: every hour)
- Startup fetch — triggers an initial full sync on the first HTTP request after deployment
- KV caching — D1 query results are cached in KV for fast API responses; cache is selectively invalidated on mutations
- Deduplication — database-level unique indexes prevent duplicate items by
(feed_id, url)and(feed_id, title) - CORS support — cross-origin requests enabled for web-based RSS clients
- Observability — structured
[INFO]/[WARN]/[ERROR]logging for Cloudflare dashboard inspection - Secure auth — constant-time string comparison for API key validation
┌──────────────────────────┐
│ Fever-compatible Client │ (Reeder, Fiery Feeds, etc.)
│ GET/POST ?api&... │
└─────────┬────────────────┘
│ Fever API protocol
▼
┌──────────────────────────┐
│ Cloudflare Worker │ Plain JavaScript (ES modules)
│ ┌──────────────────┐ │
│ │ fever.js │ │ API request routing & response
│ │ auth.js │ │ md5(email:password) authentication
│ │ fetcher.js │ │ Concurrent RSS feed fetching & parsing
│ │ feedparser.js │ │ RSS / Atom / JSON Feed parsing
│ │ db.js │ │ D1 database access layer
│ │ cache.js │ │ KV-backed cache-aside layer
│ │ var.js │ │ Runtime configuration from env vars
│ │ models.js │ │ Data models & Fever API response types
│ └──────────────────┘ │
└──────────────────────────┘
│
┌────┴────┐
▼ ▼
┌─────────┐ ┌──────┐
│ D1 DB │ │ KV │
│ SQLite │ │Cache │
└─────────┘ └──────┘
| Layer | Technology | Purpose |
|---|---|---|
| Database | Cloudflare D1 (SQLite) | Feeds, groups, items, read state |
| Cache | Cloudflare KV | Cached D1 queries for fast reads (feeds, groups, unread/saved IDs, item counts) |
| Cache strategy | Cache-aside | Read: KV → miss → D1 → backfill KV. Write: invalidate affected KV keys |
- Node.js 22.18+ (required by the
cfCLI) - A Cloudflare account with:
- Workers subscription (free plan works)
- D1 database quota
- KV namespace quota
git clone https://github.com/jyfzh/current
cd current
npm installcloudflare.config.ts is the source of truth for the Worker: bindings, the hourly cron trigger, and runtime vars. The worker is plain JavaScript, so there is no user-authored build step — npm run build (cf build) bundles src/index.js with Vite through the Cloudflare Vite plugin.
vite.config.ts configures the bundler and the local dev server port (default 8787).
npx cf d1 create --name current-dbThe command outputs a database ID. Copy it into the DB binding in cloudflare.config.ts:
DB: bindings.d1({
id: "<database-id>",
}),npx cf kv namespaces create --title current-cacheCopy the output namespace ID into the CACHE binding in cloudflare.config.ts:
CACHE: bindings.kv({
id: "<namespace-id>",
}),npx cf d1 migrations apply <database-id> --dir migrationsCreate a .secrets file (it is gitignored) in .env format:
cat > .secrets <<'EOF'
CURRENT_FEVER_PASSWORD=<your-password>
CURRENT_FEVER_EMAIL=<your-email>
EOFBoth names are declared as required secrets in cloudflare.config.ts. Upload them with --secrets-file:
npx cf deploy --secrets-file .secretsTo rotate a secret later, update .secrets and deploy with the same flag, or set one individually with npx cf workers secrets update CURRENT_FEVER_PASSWORD --text <value> --worker current.
npx cf auth login # first time only
npm run deploy # or: npx cf deployAfter deployment, your API endpoint will be:
https://current.<your-subdomain>.workers.dev/?api
curl "https://current.<your-subdomain>.workers.dev/?api&api_key=$(echo -n '<email>:<password>' | md5sum | cut -d' ' -f1)"Expected response:
{"api_version":3,"auth":1}All configuration is through Worker environment variables, set in cloudflare.config.ts with bindings.text(...) (vars) or bindings.secret() (secrets):
| Variable | Description |
|---|---|
CURRENT_FEVER_PASSWORD |
Fever API password (used with email for auth) |
CURRENT_FEVER_EMAIL |
Fever API email (default: admin. Used with password for auth) |
| Variable | Default | Description |
|---|---|---|
CURRENT_MAX_CONCURRENCY |
5 |
Max concurrent feed fetches (0 = unlimited) |
CURRENT_FEED_STALE_SECONDS |
3600 |
Min age (seconds) before a feed is eligible for re-fetch |
CURRENT_STARTUP_FETCH |
true |
Trigger initial full feed fetch on first HTTP request after deploy |
CURRENT_CACHE_TTL_AGGREGATE |
600 |
KV cache TTL for aggregate queries (total items, group counts) |
CURRENT_CACHE_TTL_STRUCTURAL |
600 |
KV cache TTL for structural data (feeds, groups, unread/saved IDs) |
CURRENT_FEVER_ITEMS_PER_PAGE |
50 |
Number of items per API response page |
Current speaks the Fever API protocol, so any RSS reader that supports Fever sync can connect to it.
- Open your RSS client's account/sync settings
- Select Fever as the sync type
- Enter:
- URL:
https://current.<your-subdomain>.workers.dev/?api - Email: whatever you set for
CURRENT_FEVER_EMAIL(default:admin) - Password: whatever you set for
CURRENT_FEVER_PASSWORD
- URL:
Open / or /admin to access the Chinese-language management dashboard. Sign in with CURRENT_FEVER_EMAIL (defaults to admin) and CURRENT_FEVER_PASSWORD.
The dashboard supports adding, editing, deleting, searching and filtering feeds; creating, renaming and deleting groups; inspecting unread counts and HTTP fetch status; and refreshing individual feeds. Deleting a group preserves its feeds as ungrouped. Deleting a feed also deletes its articles, saved state and read history, after confirmation.
Management endpoints live under /admin/api/, separate from the unchanged /?api Fever protocol. Credentials stay in page memory only; reloading requires signing in again. Use HTTPS in production. A successful HTTP status does not guarantee successful feed parsing; consult service logs for parsing details. No additional migrations or runtime dependencies are required.
For bulk maintenance, you can also add feeds directly to D1:
You can execute SQL against the D1 database using either of the following methods:
- Log in to the Cloudflare Dashboard
- Navigate to Workers & Pages → D1 → select your database
- Use the Explorer Data tab to run SQL queries interactively, or view, add, and delete rows directly through the UI
# Execute SQL directly (use the database ID shown by `cf d1 create`)
npx cf d1 raw <database-id> --sql "INSERT INTO groups (title) VALUES ('Tech');"
# Apply SQL from a file as a batch
npx cf d1 raw <database-id> --batch @queries.jsonqueries.json is a JSON array of query objects:
[
{
"sql": "INSERT INTO feeds (title, url, site_url, group_id) VALUES ('Example', 'https://example.com/feed.xml', 'https://example.com', 1);"
}
]Example SQL to add feeds:
-- Add a group
INSERT INTO groups (title) VALUES ('Tech');
-- Add a feed
INSERT INTO feeds (title, url, site_url, group_id)
VALUES ('Example Blog', 'https://example.com/rss', 'https://example.com', 1);The next cron run (or first API request if CURRENT_STARTUP_FETCH is enabled) will fetch and populate items.
From the RSS client, select the feed/group and use the "Mark as Read" action. The client sends the appropriate mark=feed&as=read&id=N&before=TS command, and Current handles it.
The Fever API protocol is fully documented in docs/fever-api.md and the OpenAPI spec at docs/fever-openapi.yaml.
| Layer | Technology |
|---|---|
| Language | JavaScript (ES modules) |
| Runtime | Cloudflare Workers |
| Tooling | cf (Cloudflare CLI, beta) |
| Database | Cloudflare D1 (SQLite-compatible) |
| Cache | Cloudflare KV |
| Feed Parsing | Built-in parser (RSS 2.0, Atom, JSON Feed) |
| Auth | MD5 (Fever protocol) |
| Scheduling | Workers Cron Triggers |
- AI-powered feed clustering — Automatically group feeds into topic clusters (e.g., Tech, Science, Politics) using Cloudflare Workers AI embeddings and Vectorize, so new subscriptions are categorized without manual setup.
- Personalized recommendations — Surface trending or relevant items based on your reading history, powered by on-device-style inference via Workers AI.
- Smart summaries & highlights — Generate concise summaries for unread items using an LLM running on Workers AI, stored back to D1 for quick recall.
- Hot topics detection — Analyze item titles and content across all feeds to identify emerging topics and spikes in coverage, delivered as a new API endpoint.
These features will leverage Cloudflare's global AI inference network, keeping data processing close to the database and minimizing latency.
MIT © 2026 jyfzh