Blog / Engineering

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 · 2026-09-29 · 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:

  1. The size was wrong. Databases were actually running at a larger default size than the estimate assumed.
  2. Databases autoscale. Under load they grow, and the estimate never saw it.
  3. 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:

  1. For each published app with a database, fetch the measured usage for every finished hour since the app went live.
  2. Convert that usage to cost at the provider's price, apply the plan's rate, and charge it to the app owner's credits.
  3. 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.

Keep reading

  • A Failed Republish Never Deletes a Working Backend — A failed republish could delete an app's live API, or leave its broken new version running. Three fixes to how Mythex undoes a publish that goes wrong.
  • Alerts That Fire Once, Not Once per Server — A once-a-day alert reached us five times in one afternoon. Why in-memory dedupe breaks with two servers and a deploy, and how shared state fixed it.
  • Moving to Bigger Workspaces Without Making Anyone Wait — A quarter of our workspaces were stuck at 1 GB after we moved to 2 GB. Our first fix made one person wait seven minutes. What we changed, and changed again.
  • Catching Apps That Crash Right After Publishing — Three publishes passed our health check while their API crashed seconds into every boot. The cause: counting crashes in a list capped at five entries.
  • Keeping Image-Heavy Agent Turns Within Memory — An agent turn that kept looking at catalogue scans ran out of memory at 952 MB. Three separate causes, each holding images too long, and how we fixed them.
  • Keeping Long Agent Turns Inside the Context Window — Our sub-agents could grow until the model refused them, stop early to save room, or miscount tokens in Russian. Three fixes that let long AI work finish.

Start building free · Templates · Docs