Self-Host Postgres Instead of Paying for a Managed Database Add-On
On most hosting platforms the database costs more than the app. If you can self-host Postgres as an ordinary container with a persistent volume, you pay container prices for it instead of add-on prices — on JustRunMy.App there's a one-click Prefab Template that does exactly this, giving you a real Postgres with its own volume and a TCP endpoint. The trade-off is honest and worth stating up front: you get no automated backups, no failover, and no private network. For a side project, a staging environment, or an internal tool, that's usually the right deal. For production data you'd cry about losing, it isn't.
What managed Postgres actually costs
Heroku's smallest managed tier, Essential-0, is $5 per month for 1 GB of storage and up to 20 connections (Heroku). That's a fair price for a fully managed Aurora-backed database. It's also more than many hobby projects spend on everything else combined — and it's per database, so a project with a staging copy pays twice.
The reason is that you're buying operations, not storage: backups, point-in-time recovery, patching, failover, connection pooling. Those are worth real money when you need them. The mistake is paying for them on a database whose entire contents you'd happily rebuild from a seed script.
The Prefab Template route
Open Prefab Template on the Advanced tab of Create new application. There's a small catalogue of ready-made apps, and Postgres is one of them.

Opening the template shows what it is and a Start button. Templates aren't just an image reference — each one carries its ports, environment variables, config files, volumes, and a set of parameters you fill in, with validation rules on the values. Deploying runs all of that in one step: it creates the app, sets the image, creates the ports, applies your parameters as environment variables, mounts the volumes, and starts the container.
So you end up with a normal application you fully control, not an opaque add-on. You can open its shell, read its logs, change its CPU and RAM, and back it up however you like.
Doing it by hand instead
The template is a shortcut, not the only way. Any Postgres image deploys the same way through Existing Image, and it's worth knowing the three pieces because they're the same three for any stateful service:
- The image —
postgres:16, or whichever tag you want. - Environment variables —
POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_DB, set as env vars. - A volume at
/var/lib/postgresql/data— this is the part that matters. Without a volume, your data lives in the container's writable layer and disappears on the next restart or image change.
Then add a TCP port binding for 5432 in the Ports panel. Postgres speaks its own wire protocol, not HTTP, so it needs TCP rather than the HTTPS binding a web app would use — the panel shows you the public host and port to connect to once it's saved.
Connecting your app — and the caveat
In your application's env vars, point DATABASE_URL (or whatever your framework expects) at the host and port shown in the database app's Ports panel:
DATABASE_URL=postgres://USER:PASSWORD@<db-host>:<db-port>/DBNAME
Here's the part to be clear-eyed about: there is no private network between apps. Every port binding gets a publicly resolvable endpoint. Your app doesn't reach Postgres over an internal-only address — it connects to the same TCP endpoint anyone else could reach.
What protects the database is its credentials, so treat that as load-bearing rather than incidental:
- Use a long random password, not
postgres. - Don't reuse it anywhere else.
- Keep it in env vars, never in your repo.
- Remove the port binding when you're not using it — a database with no exposed port isn't reachable at all.
This is the real difference from a managed add-on, which typically restricts access at the network level as well. If your threat model needs network isolation, pay for managed. If it doesn't, credentials on a TCP port is the same posture as most self-hosted databases on the internet.
What you give up
Say the quiet part out loud:
- No automated backups. Run
pg_dumpon a schedule from your app's shell or from CI, and store the dump somewhere else. If you skip this, you have no backups — nothing does it for you. - No failover or replication. One container, one node.
- No connection pooling. Add PgBouncer yourself, or keep your pool small in the app.
- No point-in-time recovery. Your recovery granularity is however often you dump.
- You own upgrades. Moving major versions means dumping and restoring into a new container.
None of these are dealbreakers for a project where the database can be rebuilt. All of them are dealbreakers for one where it can't.
The cost side
At the platform's published rates — $1.90 per vCPU-month, $1.95 per GB RAM-month, and $0.25 per GB disk-month, billed per minute — a small Postgres container with 0.15 vCPU, 0.25 GB RAM, and 1 GB disk works out to $1.02 for a full month. That's arithmetic on the posted rates, not a plan: you're paying for allocated resources, the same way you pay for any other app.
The structural point matters more than the number. A managed add-on is priced as a product. A container is priced as compute. When you genuinely need the product, buy the product — and when you need a Postgres that holds forty rows for a staging environment, don't.
FAQ
Does JustRunMy.App have a managed database?
No. There's no built-in database service — you run Postgres, MySQL, Redis, or MongoDB as an ordinary application, with a volume for its data.
How do I keep Postgres data from disappearing on restart?
Mount a volume at /var/lib/postgresql/data. Without one, the data sits in the container's writable layer and is lost when the container is replaced.
Can my app reach the database privately?
No — port bindings are publicly reachable, so app-to-database traffic goes over a public TCP endpoint. Protect it with strong credentials, and remove the binding when the database isn't in use.
Which port and protocol does Postgres need?
5432, bound as TCP. Postgres doesn't speak HTTP, so an HTTPS binding won't work.
How do I back it up?
Run pg_dump from the app's shell or a CI job and store the output elsewhere. Nothing backs it up automatically.
Is self-hosting Postgres a good idea for production?
For production data you can't afford to lose, a managed database with automated backups and failover is worth the money. Self-hosting fits side projects, staging, internal tools, and anything you can rebuild.
Wrapping up
"Self-host your database" gets pitched as a pure cost win, which undersells the decision. What you're actually choosing is whether to pay for operations — backups, failover, recovery — or to take them on yourself. A prefab template makes taking them on cheap and quick, and a volume makes it durable enough for most things. Just make the choice deliberately, and write the pg_dump cron before you need it rather than after.