Billing Databases by What They Actually Use
We used to estimate each app's database cost, and the estimate was wrong both ways. Now every database is billed from measured usage, hour by hour.
Mythex Team · · 3 min read
Every Mythex app that needs to store data gets its own Postgres database, and a published app's database usage comes out of the same credit balance as building. Until late September we estimated that usage from how long the app's server was running. The estimate turned out to be wrong in a way that mattered, so we replaced it: each database is now billed from the compute its provider actually measured, one finished hour at a time, and each hour can only ever be charged once.
How the databases work
Each database runs on serverless Postgres that scales to zero: after a few idle minutes it sleeps, and it wakes on the next query. While awake it can scale its compute up and down with load. That's what makes "a database per app" affordable — most apps are quiet most of the time, and a sleeping database costs almost nothing.
It also means the cost of a database depends on two things we can't see from outside: how long it was awake and how big it was while awake.
What the estimate got wrong
Our original meter made an assumption: for every hour a published app's server was running, charge for a database at the smallest compute size.
That was wrong in three ways:
- The size was wrong. Databases were actually running at a larger default size than the estimate assumed.
- Databases autoscale. Under load they grow, and the estimate never saw it.
- Databases don't follow the app server. A database stays awake whenever anything queries it — the app, a scheduled job, a script polling it — whether or not the app's server was up.
Net effect: the estimate charged users roughly half of what the databases actually cost. That's not sustainable for us, and it also meant usage numbers in the app didn't mean what people thought they meant.
Measuring instead of guessing
Our database provider reports each project's compute-unit-seconds per hour — how much compute it actually used, size included. So the meter now works like this:
- For each published app with a database, fetch the measured usage for every finished hour since the app went live.
- Convert that usage to cost at the provider's price, apply the plan's rate, and charge it to the app owner's credits.
- Look back up to a day each time, so hours missed while our API was restarting still get billed later.
Storage is billed separately, by size, because it doesn't depend on activity.
Never charging an hour twice
A billing meter that runs on more than one server — and can crash and retry — has to be careful not to double-charge. Each hour of each database is claimed in its own database row before it's charged, with a uniqueness constraint on the pair (database, hour). If two servers, or a retry, try to bill the same hour, only one claim succeeds.
We also made a deliberate choice about the rare failure case: if the process crashes between claiming an hour and charging it, that hour stays claimed and unbilled. Losing a sliver of revenue in a rare crash is better than ever charging someone twice.
And when measured billing switched on, it started from the next full hour. The hours before that had already been charged by the old estimate; billing them again from measured data would have charged that stretch twice.
What this means if you build on Mythex
- Your database bill now reflects what your database did. An app that's rarely used costs very little; an app that queries its database constantly will keep it awake and cost more.
- The biggest lever is how your app uses the database. Polling the database every few seconds keeps it awake around the clock. Asking the AI to fetch data on demand, or cache it, lets the database sleep. Our guide to what a database is covers the basics.
- Pro plans pay half the Free rate for hosting, databases and storage. The details are in the credits docs.
What we took from it
- Estimates of usage-based costs drift. When the upstream provider can tell you what was used, bill from that.
- Make billing idempotent at the smallest unit you charge. For us that's one database-hour.
- When you must fail, fail in the customer's favour.