Renewlet is a self-hosted subscription ledger that reminds you before renewals. Add a subscription or any recurring charge, set its renewal date and reminder days, and it will notify you through the channels you configure. You can also track price, currency, budget, logo, category, and payment method.
If you already have bill screenshots, notes, or table data, AI recognition can turn them into editable subscription drafts for review before import.
Mobile web is first-class: open it in a phone browser to add subscriptions, filter lists, review stats, and configure notifications.
Idle memory usage is around 20-30MiB in local testing, making it comfortable for small VPS, NAS, and homelab boxes.
- Track each subscription clearly: name, logo, price, currency, billing cycle, renewal date, status, category, payment method, tags, website, and notes.
- Add with AI recognition: turn bill screenshots, notes, or pasted table data into editable subscription drafts, then review and import them.
- Understand spending: normalize costs by month and year, then review budget usage, category breakdowns, payment-method charts, and inactive-subscription savings.
- Get renewal reminders: jobs are generated from each user's IANA time zone and local notification time, with reminder days, repeat reminders, delivery history, and failed-send retries.
- Subscribe from calendar apps: generate a global private ICS feed URL in settings, or create an independent per-subscription feed from a subscription card or calendar detail dialog to open the system calendar subscription flow.
- Share a public status page: publish a shareable view of the subscriptions you choose to show.
- Send notifications through seven channels: Telegram, Notifyx, Webhook, WeCom Bot, SMTP email, Bark, and ServerChan.
- Choose subscription artwork: upload a Logo, paste an image URL, search built-in icon sources, or use favicon fallback suggestions.
- Handle multiple currencies: choose Exchange API or FloatRates JSON Feeds, with fallback rates when remote providers are unavailable.
- Move subscription data in and out: export from Renewlet, import Renewlet or Wallos files, preview mapped subscriptions, and adjust Logos before saving.
- Customize your lists: categories, statuses, payment methods, and currencies can be adjusted in settings, with built-in icons for common payment methods.
- Adjust the app: switch languages, choose light, dark, or system themes, pick a color variant, and manage account password settings.
- Self-host one container: React frontend, Go/PocketBase backend, SQLite data, and static assets run together, with data persisted to
data/. - Deploy to Cloudflare Workers: React static assets, Worker API, D1, R2, and Cron Triggers can run without the Go/PocketBase server.
- Mobile-web friendly: bottom navigation, subscription cards, tag-filter drawers, and settings screens are adapted for small screens.
Click the button and follow the Cloudflare wizard for the easiest deployment path.
Do not click the one-click button again to upgrade. Use the Upgrade steps in Cloudflare Workers deploy, sync the repository Cloudflare created, and push to redeploy.
If the page says Failed to get repository contents, Cloudflare is usually being rate-limited while reading the public GitHub repository. If you are using a proxy/VPN node, a corporate or school network, or another shared network egress, the current egress IP may also be temporarily rate-limited by GitHub or Cloudflare. Avoid repeated retries; try again later, switch to a more reliable proxy node or network egress, or use Cloudflare Workers manual deploy.
On a machine with Docker and Docker Compose v2:
mkdir -p renewlet && cd renewlet
curl -fsSL https://raw.githubusercontent.com/zhiyingzzhou/renewlet/main/deploy/docker-deploy.sh | bash
docker compose up -dThen open:
http://localhost:3000/setup
Create the first admin user. The deploy script creates docker-compose.yml, .env, and data/, then generates PB_ENCRYPTION_KEY and CRON_SECRET for you.
If Docker Hub is unavailable, switch the image in .env to GHCR:
RENEWLET_IMAGE="ghcr.io/zhiyingzzhou/renewlet:latest"Then pin a released version when you use Renewlet in production, pull, and restart:
sed -i.bak 's#RENEWLET_IMAGE=.*#RENEWLET_IMAGE="ghcr.io/zhiyingzzhou/renewlet:0.1.0"#' .env
docker compose pull
docker compose up -dFor production, prefer a concrete stable version tag such as 0.1.0.
Back up data and config before upgrading:
If you deployed Renewlet before 2026-06-04, open the old version before upgrading and use Export subscriptions -> JSON to save subscriptions.json. After upgrading, import that old JSON from Import data. This file is for subscription-data migration only; keep the .env, docker-compose.yml, and data/ backup below as well.
tar -czf renewlet-backup-$(date +%F).tgz .env docker-compose.yml dataUpgrade to a specific version with Docker Compose:
sed -i.bak 's#RENEWLET_IMAGE=.*#RENEWLET_IMAGE="zhiyingzzhou/renewlet:0.1.0"#' .env
docker compose pull
docker compose up -d
docker compose logs -fOfficial Docker release images with the current binary layout can also update from the version badge at the top of Renewlet, which opens System Update. This in-app path downloads the GitHub Release binary, verifies checksums.txt, replaces the runtime binary, and then asks an administrator to click Restart now. Older images must run docker compose pull && docker compose up -d once before the in-app updater becomes available.
Cloudflare deployments update from the repository connected in Cloudflare Builds. One-click deploy users sync the generated repository; manual deploy users sync their fork and run Cloudflare Worker. The deploy path must keep D1 migrations before Worker deploy.
Check status and logs:
docker compose ps
docker compose logs -fStop the service while keeping data:
docker compose downCommon settings live in .env:
| Variable | Purpose |
|---|---|
PORT |
Public port, 3000 by default. |
RENEWLET_IMAGE |
Docker image, zhiyingzzhou/renewlet:latest by default. |
TZ |
Container time zone, mainly for logs; reminders use each user's time zone. |
PB_ENCRYPTION_KEY |
Encryption key for sensitive PocketBase settings. Do not rotate it casually after deployment. |
CRON_SECRET |
Bearer secret for external Cron calls to /api/cron/notifications. |
NOTIFICATION_SCHEDULER_ENABLED |
Enables the built-in notification scheduler. Defaults to true. |
The full Docker environment template is in .env.example.
AI recognition
|
Public subscription status page
|
Subscriptions
|
Statistics
|
Renewal Calendar
|
Notifications
|
Mobile subscriptions
|
Mobile notification methods
|
Issues, docs improvements, tests, and pull requests are welcome. For larger changes, please open an issue first with the goal, use case, and rough approach so the direction can be aligned before implementation.
- LINUX DO: Renewlet recognizes and thanks the LINUX DO community for supporting open-source project discussion.
Renewlet is open-sourced under the MIT License.








