A backend where your queries are functions that re-run automatically when their data changes, so the client stays live without you writing subscriptions.
Build me the reactive backend I actually need instead of Convex — and be honest about the verdict. What you are paying for is **automatic invalidation**: the platform knows which queries a write affects and re-runs exactly those. Reproducing that properly means tracking read dependencies per query execution and matching them against writes, which is real work. The pragmatic version — declare what each query depends on — gets ninety per cent of the benefit for a tenth of the effort, and that is what this builds. STACK - Node 20+ with Fastify - SQLite through better-sqlite3, WAL mode. One writer, serialised, which makes the whole model simpler - Server-sent events for pushing to clients: one connection, no protocol to implement, and it reconnects itself - Caddy in front THE SHAPE - Queries and mutations are functions on the server, not SQL in the client. The client calls them by name with arguments - A mutation runs in a single transaction. If it throws, nothing happened — that is the transactional guarantee, and SQLite gives it to you for free - A query is pure and read-only, and can therefore be re-run and cached safely - Every function declares the tables and, where possible, the keys it reads. That declaration is what makes invalidation possible INVALIDATION - After a mutation commits, collect the tables and row keys it wrote - Match them against the declared dependencies of every live subscription, and re-run only those queries - Re-run, compare the result to what the client last received, and push only if it changed. That last check removes most of the traffic - The pragmatic middle ground: declare dependencies at the table level to start, and narrow to keys for the queries that turn out to be hot. Table-level invalidation over-fires, and over-firing is far safer than missing - Write down the rule: if a function reads something it did not declare, the client will silently go stale. Make the declaration part of the function's definition so it cannot be forgotten, and add a development-mode check that compares the declared set to what was actually read SUBSCRIPTIONS - The client subscribes to a query with arguments; the server keeps the arguments, the declared dependencies and the last result hash - One event stream per client, multiplexing every subscription - On reconnect the client re-subscribes and gets current results immediately, so a dropped connection is invisible - Authorisation checked at subscription time and again on every re-run, so a permission change takes effect at once SCHEDULING AND JOBS - A queue table with a lease, retries with backoff, and idempotency keys - Scheduled functions with a cron expression and a time zone - A mutation can schedule work to run after it commits, which is the correct place for side effects — sending an email inside a transaction that later rolls back is the classic bug this avoids THE REST OF THE BACKEND - Schema as migrations applied once, in order, from files - Authentication with sessions as long random tokens stored hashed, argon2id for passwords, rate limits on every auth route - File storage on disk by hash, served through a permission check - Every function is ordinary code in your repository, deployed by your deploy. No separate platform THE HONEST LIMIT - One process and one SQLite file means one machine. That is fine for a very large number of applications, and it does not scale sideways - Write down what you would do next — read replicas, or a client-server database with the same schema — so the simple choice is deliberate rather than accidental OPERATIONS - .env: DATABASE_PATH, BASE_URL, SESSION_SECRET, HASH_SALT - Migrations on boot, each once; nightly backup with continuous replication, and a tested restore - Health endpoint reporting live subscriptions and queue depth WHAT MATTERS MOST Dependency declaration and the development-mode check that catches a missing one. An under-declared dependency means a client that quietly shows stale data, which is the worst failure mode this design has.
What you lose
- Automatic invalidation, where the platform knows which queries a write affects and re-runs only those
- Transactional guarantees across functions without you reasoning about them
- A scheduler, file storage and search wired into the same model
If you would rather not build
- Postgres NOTIFY plus server-sent events
- Polling, which is fine more often than people admit
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $25/mo | — | 15 Aug 2026 |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
Supabase
$0Postgres with realtime subscriptions driven by replication.
supabase/supabasefree · open source
ElectricSQL
$0Syncs Postgres subsets to clients with conflict-free local writes.
electric-sql/electricfree · open source
Why this verdict
our own opinion · changed only by a person
52/100
Verdict kinda at 52. Reactivity by hand is entirely doable and the prompt shows the shape; automatic invalidation is what you are actually paying for.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Convex
answered from the record above
Is Convex free?
No — the plan we track is $25 a month. Professional from around $25 per member per month billed monthly, plus usage.
Can you replace Convex by building your own?
ALMOST. A weekend of work, and real gaps remain. Replacement score 52 out of 100, build time a weekend. Read what you lose before you decide.
How much does Convex cost?
$25 a month on Professional — $300 a year. Recorded 10 Aug 2026.
What do you lose by replacing Convex?
Automatic invalidation, where the platform knows which queries a write affects and re-runs only those; Transactional guarantees across functions without you reasoning about them; A scheduler, file storage and search wired into the same model. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Convex?
Yes: Supabase, ElectricSQL. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

