mepa8
Vendor catalog · Full connector

How to cap your Neon bill

A serverless database is only cheap when it sleeps. One polling loop keeps it awake all month, and the console will not tell you which one.

By Ryan Bolden with NousPublished Updated

Neon is a serverless Postgres vendor that separates storage from compute and bills the two apart. Storage is cheap and predictable. Compute is metered by the hour at whatever size the autoscaler chose, and it only costs nothing while the endpoint is suspended. So the bill is really a single question: how many hours a month was the database awake, and at what size.

What Neon actually bills you for

The Neon pricing page lists a Free plan with 100 compute-unit hours per project and 1 GB of storage per project, with scale-to-zero after 5 minutes that cannot be turned off. The paid plans have no monthly minimum and charge per unit: Launch at $0.106 per CU-hour and Scale at $0.222 per CU-hour, both with storage at $0.35 per GB-month and network at $0.10 per GB beyond 500 GB included.

A CU is a compute unit, and the autoscaler moves between the minimum and maximum you set. The arithmetic is unforgiving. On the Scale rate, a database that never sleeps at 0.5 CU costs 0.5 times 720 hours times $0.222, which is about $80 a month before storage. The same database on Launch costs about $38. Paid plans also offer spending notifications, which is an email, not a cap.

Neon's own console shows usage since the billing period started, and its docs on monitoring billing and usage warn that “Usage is shown since the start of the current billing period. Metrics may be delayed by about an hour and are not updated for inactive projects.” An hour of delay is fine for a bill. It is useless for catching the process that keeps the compute awake.

What happened to us

Our CRM database on Neon's Scale plan was on pace for $93 a month against a $50 budget, averaging 0.64 CU around the clock with an autoscale range of 0.25 to 2 CU. It had been quietly near $100 a month before anyone looked. The compute never slept because a scheduler rewrote a phone-index table every 5 seconds, and every rewrite touched every row whether the row had changed or not.

The numbers from inside Postgres told the story in one query. The table phone_index showed 251 updates per minute and 508 MB of bloat on a table that fit in 4 MB. The whole database was 3,375 MB. After backing up and dropping four dead monitor tables, rebuilding the index and adding 30-day retention to a log table, it was 1,210 MB. We capped the autoscaler at 0.25 to 0.5 CU and confirmed from the database that the cache limit dropped to 1.6 GB.

The code fix was merged the same day, but the hosting platform that deploys it was paused on an unpaid invoice. So on October 8, 2026 we added a BEFORE UPDATE trigger that cancels any update changing nothing but the timestamp. The check went from 251 updates in 60 seconds to 0 in 60 seconds, and a real name change inside a rolled-back transaction still affected 1 row. Rollback is one DROP TRIGGER statement, written at the top of the function.

How Mepa8 watches Neon

Neon is a full-connector vendor. The connector does not wait an hour for the console. It runs three queries against the database itself: the postmaster start time, which tells you whether the compute ever suspended; the database size, which catches bloat coming back; and pg_stat_user_tables for the hottest table, which turns into an updates-per-minute figure between runs. It also reads neon.max_file_cache_size, because that setting moves with the maximum CU and reveals when someone raised the cap.

The alerts are the ones we wished we had in August: churn above 50 updates a minute, size above 2,000 MB, a cache limit larger than 0.5 CU implies, and an on-pace figure over budget. The kill for a database is deliberately soft. Rotating the connection string or revoking the role takes the CRM offline for every reader at once, so the card says so in plain words, and the two-step confirm with a single-use token stands between a bad alert and a dark application.

Set a cap in five minutes

  1. Create a read-only Postgres role for monitoring. Mepa8 needs pg_stat_user_tables, pg_database_size and pg_settings, nothing more. Store the connection string under its env name only.
  2. Set the autoscaler maximum to what the app needs, not what the plan allows. Each extra CU-hour on Scale is $0.222, and an unused ceiling is where runaway loops hide.
  3. Set a Mepa8 budget at the sleep-and-wake number you expect, then let the first week of on-pace readings tell you whether the compute is sleeping at all.
  4. Find every poll under 60 seconds in your code and ask what it is for. Ours was a 5-second meter that needed to run once a minute.
  5. Turn on Neon's spending notifications from the billing page as a second line, and treat them as a lagging signal.

Questions people ask

Does Neon have a hard spend cap?

No. The pricing page lists spending notifications on the paid plans, which email you at thresholds, and the Free plan has fixed limits of 100 CU-hours per project. A hard dollar stop does not exist, so the cap has to live in your autoscaler maximum and your alerts.

Why read the database instead of the Neon console?

Because the console's usage metrics are, in Neon's own words on the monitoring page, delayed by about an hour and not updated for inactive projects. A query against pg_stat_user_tables answers in milliseconds and names the table.

Is Launch or Scale the right plan for a small CRM?

Launch bills $0.106 per CU-hour and Scale $0.222 on the pricing page. Our five projects used no Scale-only feature, so moving would roughly halve compute cost. That is a plan change, which belongs to the account owner, not the monitor.

Sources

  1. Neon pricing — plan rates, Free limits, scale-to-zero
  2. Neon docs: monitoring billing and usage — console delay, where metrics appear
  3. Mepa8 incident: the $100 database — our own account, October 2026

Change log: October 9, 2026 — First published from our own October 2026 accounts.