A small, installable web app for keeping track of your houseplants and when to water them. Built for phones (Android and iPhone), works offline, and needs no account and no API keys.
Use it: https://timoneiro.github.io/fronds/ → open on your phone → Add to Home Screen.
- Today view — what needs water now and what's coming up this week; one tap to log a watering, "Later" to snooze a plant whose soil is still moist, "Water all" for a watering round.
- Plant collection — name, species, room, photo and notes, grouped by room and searchable.
- Built-in care guide for ~60 common houseplants: light, humidity, difficulty, a care tip, a baseline watering interval and pet toxicity (ASPCA). Works offline.
- Wikipedia descriptions and photos for any species — including ones outside the catalog.
- Adaptive watering — after a few waterings, fronds suggests an interval based on what you actually do.
- Calendar reminders — "Add to Google Calendar" link per plant, or download an
.icsfile for Google/Apple Calendar with every plant's recurring watering. - Backup & transfer — export a single JSON file and import it on another device. Imports merge record-by-record (newest edit wins, deletions included), so it's safe to import the same file twice. Automatic safety snapshots are kept before risky operations.
- Share links — send a friend a read-only copy of your collection (pick rooms; watering dates and
notes are optional). The plants travel inside the link's
#fragment, so no server ever sees them. The friend can copy any plant into their own collection. - Optional sync & push reminders — run the small fronds server (one Docker container, e.g. on a home NAS) to share one collection between the phones in a household and get a daily notification when plants need water. One server can host several separate households; phones join with one-time invites and can be removed individually. No accounts, no third-party keys.
- What's new — after an update the app shows what changed (changelog), and you can subscribe in Settings to get a short email when a new version comes out.
Everything is stored locally in your browser (IndexedDB). Nothing is sent anywhere except species look-ups to Wikipedia — and, only if you connect one, your own sync server. If you subscribe to update emails, your address goes to Buttondown (the newsletter service), never to the app; unsubscribe from any email. Browsers can evict site data under storage pressure — especially iOS Safari — so install the app to your home screen and export a backup now and then.
fronds updates itself, like any website: when a new version is published, the app picks it up the next time it's opened. Your plants are never touched by an update. They stay in your browser, and data changes between versions are designed to keep everything you've stored. All the code is public in this repo, changes reach the app only through reviewed pull requests that pass the automated tests, and every user-facing change is listed in the changelog and in the app's What's new.
Found a security problem? Please report it privately, as described in SECURITY.md.
The app works on its own. Run a fronds server if you want the phones in your home to share one plant collection and a daily notification when plants need water. One server can also host other households (family, friends), each completely separate from yours.
Setup takes about 15 minutes. You need:
- A computer that's always on, with Docker: a NAS (Synology, Ugreen, QNAP… usually have a Docker app), a Raspberry Pi, a home server or an old PC.
- A free Tailscale account. It gives the server a private HTTPS address
your phones can reach from home or away. (The app runs on an
https://site, and browsers only let it talk tohttps://servers. Tailscale is the easiest way to get that; any reverse proxy with a certificate works too.)
Create a folder (e.g. fronds) with this docker-compose.yml:
services:
fronds:
container_name: fronds
image: ghcr.io/timoneiro/fronds-server:latest
pull_policy: always
ports:
- 8787:8787
volumes:
- ./data:/data
environment:
- TZ=Europe/London # your timezone — reminders are sent in it
- ALLOWED_ORIGINS=https://timoneiro.github.io
restart: unless-stoppedStart it with docker compose up -d in that folder, or create a "project"/"stack" from this file
in your NAS's Docker app. Everything the server stores lives in the data folder next to it.
-
Install Tailscale on the server machine and on every phone that will use fronds, and sign in to the same account on all of them.
-
In the Tailscale admin console, enable MagicDNS and HTTPS Certificates.
-
On the server machine, run:
tailscale serve --bg --https=10443 localhost:8787
On a Linux host you may need
sudo. If Tailscale itself runs as a Docker container (common on NAS), run the command in that container's console instead; the container must usenetwork_mode: hostso thatlocalhost:8787reaches fronds. -
Your server address is now
https://<machine-name>.<your-tailnet>.ts.net:10443. Find the exact name in the admin console under Machines. Open the address on your phone: you should see "fronds sync server is running".
- Find the server code in the server's log:
docker logs fronds, or the container's log view in your NAS app. Look for a line likeServer code: K7QM-2XRP-9HTW. - On your phone, with Tailscale on, open fronds → Settings → Sync & reminders → Create a household.
- Enter the server address, the server code, a name for your household and a name for this phone, then tap Create household. The plants already on your phone are uploaded. A safety copy stays on the phone first.
- On a phone that's already connected: Create invite → Share invite link.
- On the new phone (Tailscale on), open the link, check the phone's name and tap Join household. You can also paste the link or type the code in Join a household.
Each invite works once and expires after 7 days, so create one per phone. Every phone gets its own access. Phones in this household lists them all, and you can remove one at any time (a lost phone, someone moving out). A removed phone keeps its plants but stops syncing.
On each phone: Settings → Daily watering reminder → pick a time → Turn on → allow notifications → Send test.
- iPhone: first add fronds to the Home Screen (Safari → Share → Add to Home Screen) and open it from there. iOS only allows notifications for installed web apps (iOS 16.4+).
- Android: works in Chrome. Installing the app is recommended.
Reminders arrive even when a phone isn't on Tailscale. Waterings logged while away wait on the phone and sync the next time it's connected, and the phone double-checks them before showing a reminder, so you won't be told to water a plant you already watered.
Give someone the server address and the server code. They install Tailscale (you can share the server machine with them, or add them to your tailnet), then follow step 3 to create their own household and step 4 to add their phones. They can't see your plants and you can't see theirs in the app. Only share the server code with people you trust to create households. As the server's owner, you can technically read the data file.
If the server is reached at a different address (a new tailnet, machine name, port or reverse
proxy), each phone goes to Settings → Sync & reminders → Change address and enters the new
one. Phones keep their household and access, and nothing is uploaded again. Moving to a different
machine works the same way, as long as you copy the whole data folder over first: a fresh server
doesn't know your household, and fronds refuses to switch to it.
- Update:
docker compose pull && docker compose up -d, or redeploy in your NAS app (pull_policy: alwaysfetches the latest image). Your data and codes are kept. - Back up the
datafolder. It holds everything, includingsecrets.json. If you lose that file, every phone has to join again. The server also keeps a daily copy of its data indata/backups/for the last 7 days.
See the server README for configuration options, Tailscale Funnel (reaching the server without Tailscale on the phone), and the API.
- Google Drive backup — sign in with Google only if you want it; stores the same backup file in the app's private Drive folder.
- Care tasks beyond watering (fertilising, repotting, misting), seasonal interval adjustments, photo timeline.
npm install
npm run dev # http://localhost:5173
npm test # unit tests (Vitest)
npm run lint # oxlint
npm run typecheck
npm run build # production build into dist/Stack: React + TypeScript + Vite, Dexie (IndexedDB), vite-plugin-pwa, React Router (hash routing so
deep links work on GitHub Pages). Pushes to main are tested and deployed to GitHub Pages by
.github/workflows/deploy.yml.
src/
db/ Dexie schema (append-only versions), write actions, backup import/export, snapshots
domain/ pure logic: watering schedule, backup merge, calendar export (unit-tested)
species/ bundled care catalog + Wikipedia client
sync/ sync client, push reminders, reminder check (shared with the service worker)
ui/ pages, components, hooks
sw.ts service worker: offline cache + push notifications
server/ optional sync & reminder server (Node, runs the shared domain code directly)
Append an entry to src/species/catalog.ts. wiki must be an existing
English Wikipedia article title; pet toxicity should follow the
ASPCA plant list.
PRs welcome.
fronds is free, open source and ad-free, and it will stay that way. If it has kept a plant or two alive for you and you'd like to say thanks, you can buy me a coffee on Ko-fi ☕. Completely optional, and much appreciated.
Bug reports, ideas and species additions are just as welcome: open an issue.