Should Your Database Live on the Same VPS as Your App?
Cloud

Should Your Database Live on the Same VPS as Your App?

The pitch for co-location is real: no network hop, no egress bill, one box to back up. So is the failure mode — one OOM event takes the app and the database down together, because they were never separate to begin with.

Published September 28, 202611 min readUpdated Sep 6, 2026

Written by · Full-Stack Agentic AI Software Engineer — AI Agents, Automation & Revenue Systems for GTM/RevOps teams

In brief

Should I run my database on the same server as my application, or split them onto separate boxes?

Put them on the same box until a specific, measurable signal tells you to stop — not on a schedule, not because a tutorial said so. Co-location removes a network hop and its latency, removes egress charges between app and database entirely, and turns your backup problem into one disk instead of two. The cost is that app and database now compete for the same RAM and page cache, a runaway process can OOM-kill Postgres as collateral damage, you can't scale compute and storage independently, and restoring the box means restoring both at once whether you needed to or not. The signal to separate them is concrete: your database's own memory needs (shared_buffers plus working set) and your app's memory needs, added together, exceed what a single tier gives you with headroom to spare.

  • Co-location removes a network hop, removes egress charges between app and database, and reduces your backup surface to one disk instead of two
  • App and database on one box compete for the same RAM and OS page cache — there is no isolation between them unless you impose one
  • The Linux OOM killer does not know which process is more important; a memory leak in your app can take Postgres down with it
  • You cannot resize CPU for the app without also resizing whatever plan the database sits on, even when only one of them actually needs it
  • The concrete signal to split them: app memory need plus database shared_buffers plus working set exceeds your current tier with no comfortable margin left

Evidence notes

shared_buffers guidance

PostgreSQL's own resource-consumption docs recommend roughly 25% of system RAM as a starting point for shared_buffers, which is the number that makes co-location's RAM math concrete rather than vague.

Contabo Cloud VPS 4

4 vCPU / 8 GB RAM / 100 GB SSD at €5.50/month for the first 24 months, verified against Contabo's own pricing page in September 2026 — the tier where this co-location question is most often actually being asked.

Put them on the same box. That's the position, stated up front instead of buried under six paragraphs of both-sidesing: for a bootstrapped SaaS running on a single Contabo Cloud VPS 4 (4 vCPU, 8 GB RAM, 100 GB SSD, €5.50/month for the first 24 months, per Contabo's own pricing page as of September 2026), your app and your Postgres instance belong on the same VPS, right up until one specific number crosses a line I'll give you later in this post. Most advice on this question hedges because the honest answer is 'it depends,' and then never says on what. It depends on one thing: whether the two workloads' combined memory need still fits comfortably in what you're renting.

What actually gets better when they share a box?

Three things, and they're real, not theoretical. First, latency: a query from your app to a database on the same host goes over a loopback interface or a Docker bridge network, which is microseconds, versus a query to a database on a separate host on the same provider's network, which is typically low single-digit milliseconds, and a database on a different provider entirely can be worse than that by an order of magnitude. For a request path that runs a dozen queries, that difference compounds into something a user notices. I write about self hosting from the build side; XenGrowth's growth engineering practice covers what it takes to run it.

Second, egress. Move the database off-box and every query response now crosses a network boundary that some providers meter. Contabo advertises unlimited traffic on its plans and, per its own support documentation, applies no default bandwidth limit at all — just a fair-use policy it enforces at its discretion, which a database's own query traffic on a same-provider setup will never come close to troubling. The moment your database lives with a managed provider instead, that data movement can be billed outright, and it's billed in the direction that hurts most: reads, which is most of what an app actually does.

Third — and this is the one people undercount — co-location means one thing to back up, not two. A single `pg_dump` or volume snapshot captures everything your stack needs to come back. Split the database onto its own host and you now have two backup schedules, two restore procedures, and two systems that need to agree with each other on the day you actually need them, which is a coordination problem you didn't have before and won't remember exists until it matters.

  • No network hop between app and database — queries run over loopback or a container bridge, not a real network link

  • No egress charge on database traffic, because there's no boundary for that traffic to cross

  • One host to patch, monitor, and secure instead of two

  • One backup schedule and one restore procedure to actually keep tested

  • Lower total spend at small scale — you're not paying for a second always-on instance to hold data that would fit comfortably next to the app

What actually breaks when they share a box?

None of the three benefits above are free lunches, and pretending co-location is strictly better than splitting is the same mistake as pretending it's strictly worse. It's a genuine trade, and the cost side of that trade is where most co-location advice goes quiet. The XenGrowth resource library works through the operations side of this in more operational detail.

Here's the part the pitch above leaves out. Your app and Postgres are not two isolated tenants — they're two processes drawing from one pool of RAM and one OS page cache, and neither one knows the other exists. Postgres reserves shared_buffers at startup, conventionally around a quarter of total RAM, and it expects the rest of memory, mostly the OS page cache, to still be available for its own working set. Your app doesn't know that reservation exists. Give it a memory leak, an unbounded cache, or just a traffic spike that grows its heap, and it will happily eat into the RAM Postgres was counting on, with nothing in the system stopping it.

That leads to the failure mode that actually matters: the Linux OOM killer doesn't care which process is your database and which is your app. When physical RAM plus swap runs out, the kernel picks a victim based on a scoring heuristic, and there's no guarantee it spares Postgres because Postgres is more important to you. A leak in your Next.js server can get Postgres killed as collateral damage — the exact process you most needed to stay alive is not exempt just because it deserves to be. That mechanism is worth understanding on its own terms, and I've written up exactly how the OOM killer decides in what actually happens when a VPS runs out of RAM.

The second cost is that you can't scale the two independently. Say your app starts serving ten times the traffic but your data volume hasn't grown at all — the honest fix is more app compute, not a bigger database. On a shared box, there's no such thing as 'more app compute' without also carrying a bigger database allocation you didn't need, because they're the same box, sized once, for both. The inverse is just as common: your dataset grows and your working set no longer fits in shared_buffers, but your app's own memory footprint is still small. You're stuck upgrading the whole tier for a need that belongs to one half of it.

The third cost is the one people feel hardest on the actual bad day: a restore is all-or-nothing. If the box needs to be rebuilt — disk failure, a botched update, a compromised server — you're restoring the app and the database together, in whatever order your restore script assumes, even if only one of them actually broke. There's no partial restore of 'just the database, the app was fine.' They fail as a unit because they were never anything but a unit. XenGrowth on governed AI marketing workflows approaches this from the AI agents and marketing automation side.

There's a fourth cost that's easy to miss because it's slower and quieter than the other three: noisy-neighbor CPU contention during anything unusual. A migration running against a large table, a burst of report queries, a backup job doing a dump — all of these are legitimate, occasional database work that briefly wants real CPU, and on a shared box they're competing with whatever your app is doing for the same visitors at the same moment. Split onto separate hosts and a heavy migration slows down the migration. Co-located, it can slow down page loads for everyone using the app while it runs, which is a worse trade than it sounds like until you've actually watched it happen during a deploy window.

Dimension

Same box

Separate boxes

Query latency

Microseconds, loopback or bridge network

Low single-digit ms same-provider, worse cross-provider

Egress cost on DB traffic

None — no boundary to cross

Metered on most managed providers, absorbed on same-provider VPS-to-VPS

Blast radius of an OOM event

App leak can take the database down with it

App and database fail independently

Independent scaling

Not possible — one tier sizes both

App and database each scale on their own schedule

Backup and restore surface

One schedule, one procedure

Two schedules that must agree with each other

Monthly cost at small scale

Lower — one always-on instance

Higher — a second instance running whether or not it's needed

The actual signal that says separate them

Not a traffic number, not a revenue number, not 'when it feels serious.' The signal is arithmetic you can do today: add your app's steady-state memory footprint to Postgres's shared_buffers plus the working set it needs cached to avoid constant disk seeks. If that sum comfortably fits inside your current tier with real headroom left over — say 30% free, not 5% — stay co-located. The moment that sum regularly pushes past what's left after the OS itself, you don't have a co-location preference problem anymore, you have a genuine resource contention problem, and no amount of tuning `work_mem` or restarting the app fixes arithmetic.

The wrong question is 'is my app getting slow.' The right question is 'does swap usage on this box creep up over days, independent of any one bad afternoon.' The first is noise. The second is the actual number that predicts when co-location stops working.

There's a softer version of the same signal worth watching before the hard one arrives: sustained swap usage. Any VPS with co-located Postgres and app that shows swap climbing steadily, not just during a spike, is telling you the two workloads are already fighting for the same RAM more often than they're finding enough of it. That's the moment to plan the split, not the moment you're forced into it during an outage. If AI search, GEO and discovery is the part you are stuck on, XenGrowth on building one SEO and GEO content system is the better reference.

Situation

Verdict

Solo project or early-stage SaaS, one Contabo Cloud VPS 4-class tier, low-to-moderate traffic

Co-locate — the operational simplicity outweighs the theoretical risk at this scale

Traffic grew, but your dataset is still small

Co-locate, but upgrade the app-facing side (more vCPU, same RAM) if a bigger tier lets you

Dataset grew, working set now regularly evicts from shared_buffers

Consider a bigger tier first; move the database only once a bigger tier stops being enough

Swap usage trending upward across weeks, not just spiking

Split — this is the concrete signal, not a guess

Multiple apps sharing one Postgres instance, one of them noisy

Split the noisy app's database out first, before splitting everything

Compliance or blast-radius requirements demand the database survive an app-level compromise

Split regardless of memory math — this is a different kind of requirement entirely

What splitting them actually buys you, and what it costs

Once you do split, the app and database can be sized, patched, and restarted independently, and an app-level incident stops being a database-level incident by default. That's a genuine architectural upgrade, not just more hardware. It's also not free: you've added a network dependency between two things that used to be one, you've doubled your patching and monitoring surface, and — this is the part people forget — you've reintroduced the exact network latency and egress cost that co-location was removing in the first place. Splitting isn't strictly better. It trades one set of problems for a different set, and the trade only pays off once the co-located version's problems have actually started to bite.

There's a version of this decision that skips the VPS question entirely: paying a managed provider to run Postgres for you, so neither co-location nor a self-managed split is even on the table. That's a real third option, with its own cost curve and its own tradeoffs around connection pooling, cold starts, and backups — I've laid it out against a plain self-hosted VPS in the managed-versus-self-hosted comparison, because it deserves its own numbers rather than a paragraph tacked onto this one.

There's a version of the trade that avoids both extremes worth naming here too: keeping app and database on the same VPS while still running Postgres inside its own container with an explicit memory limit set. That doesn't remove the shared RAM pool at the OS level, but it does mean a leak in the app container hits its own ceiling instead of quietly eating into what Postgres was counting on — a cheap partial mitigation while you're still below the threshold that justifies a full split. If you're still deciding whether to self-host at all versus pay someone else to carry the operational load, that's a broader question than this post, and I've written a separate rule for it: my rule for deciding what to self-host and what to keep paying for. This post assumes you've already decided to self-host and just need to know whether the database belongs next to the app or away from it — and for the size of project this cluster is written for, it belongs next to it, until the arithmetic says otherwise.

Further reading from XenGrowth

Where this work meets go-to-market

For the marketing and revenue operations view of self hosting, see XenGrowth, who work on the commercial side of this.

Should you actually split them?

Five questions about the concrete signals the post argues for, not a schedule or a feeling. It applies the same rule — co-locate until arithmetic or a hard requirement says stop.

1 / 5
Does your app's memory need plus Postgres's shared_buffers and working set comfortably fit your current tier?

Comfortably means real headroom left, not 5% free.

Apply this article

How to turn insights into execution

A practical sequence for teams turning concepts into production outcomes.

PostgreSQLVPSself-hostingarchitecturecapacity planningCoolifycloud

Audit your current state

Map the bottlenecks and constraints connected to the article’s core problem.

Choose one bounded change

Test the most useful recommendation on one workflow before widening the scope.

Measure what changed

Keep the parts that improve the work, document what failed, and make the next decision from evidence.

Next step

Need help applying this in your stack?

I can translate these patterns into a concrete implementation plan for your team.

Discuss implementationBack to blog

Replies usually within 24 hours.

Next Steps

Continue reading

The Simplest Production Architecture for a Bootstrapped SaaS

One box, a handful of managed pieces around the edges, and a very short list of things you're not allowed to build yet. Here's the architecture, priced out to $20 a month, and the exact signal that tells you when to add each thing you skipped.

Navigate

The Backup Strategy Every Self-Hosted SaaS Needs (3-2-1, Applied)

3-2-1 is easy to nod along to and easy to get wrong in the specific way that only shows up on the day you need it. Here's what it actually means for one VPS running Postgres and Docker volumes, not the generic version you've already skimmed past twice.

Navigate

My Complete Self-Hosted Stack for SaaS in 2026

Contabo, Coolify, Docker, Cloudflare, Postgres, R2, Resend, Uptime Kuma, Turborepo and Docker Hub. Here's every piece of the stack I actually run, what each one replaced, and why I picked it over the alternatives.

Navigate

vCPU or RAM? How to Size a VPS for Static Sites, Databases and Traffic Spikes

Four readers asked four versions of the same question, and each one has a different honest answer. Static files want RAM for page cache, Postgres wants RAM for shared_buffers, and "slow under traffic" is usually neither CPU nor RAM.

Navigate

Moving a SaaS Off Vercel to a €5.50 VPS: What the Numbers Actually Look Like

Nobody publishes their real Vercel invoice, so most migration posts trade in vibes instead of arithmetic. This one builds the comparison from Vercel's and Contabo's own published rates, states every assumption out loud, and shows exactly where the two lines cross.

Navigate

My Free Monitoring Stack for Self-Hosted Apps

Vercel gives you monitoring whether you ask for it or not. A VPS gives you a blank terminal and the assumption you'll figure it out. Here's what to actually watch on a self-hosted box, with tools that cost nothing, and why watching from the box itself is the one setup that will lie to you.

Navigate

Best VPS Providers for Coolify: Contabo, Hetzner and the 2026 Price Shift

Every 'best VPS for Coolify' post still says Hetzner is the cheap option. That stopped being reliably true in June 2026 for two of its most popular tiers, and nobody's updated the recommendation yet.

Navigate

The 80/20 Self-Hosting Stack for Indie Hackers

Most self-hosting advice is all-or-nothing: run everything yourself, or don't bother. Neither is right. Here's the specific 20% of self-hosting effort that actually delivers 80% of the savings, and the parts not worth touching.

Navigate

Coolify vs Dokploy: Which Self-Hosted PaaS Should You Run in 2026?

I run Coolify on my own box and I'd still tell most people starting today to look hard at Dokploy first. Here's the actual decision, not a feature-for-feature tie.

Navigate

The Contabo + Coolify + Cloudflare Stack That Replaced My Vercel Bill

Three pieces, not thirty. Here's exactly what each one does, why that specific combination and not one of the dozen others I considered, and which parts of Vercel each one is actually standing in for.

Navigate