- DBLab: Save €55/mo with PostgreSQL Instant Clones Now
DBLab: Save €55/mo with PostgreSQL Instant Clones Now
Use DBLab's ZFS-powered PostgreSQL cloning on a €5 Hetzner VPS to replace Neon branching, get one-second dev clones…

📚 Get Practical Development Guides
Join developers getting comprehensive guides, code examples, optimization tips, and time-saving prompts to accelerate their development workflow.
I Was Paying €60/Month for a Dev Database. Here's the Open-Source Alternative I Found.
You can replace Neon's database branching with a self-hosted DBLab Engine on a €5/month Hetzner VPS and get the same workflow — instant clones from production data, per-developer isolation, and one-second resets — for a fraction of the cost. This guide walks through how DBLab works, why it replaces the specific Neon feature I actually used, and what the daily workflow looks like in a Payload CMS project.
The €60 wake-up call
When I started building projects on Vercel, Neon was the obvious database choice. Free tier, zero config, managed PostgreSQL — what's not to love? The developer experience was genuinely great. You get database branching, instant clones for development, and you never think about infrastructure.
Then my projects started getting real traffic.
The first month the bill crossed €40, I noticed. By the time it climbed past €60 for a single PostgreSQL instance, I started asking questions. The price wasn't unreasonable for a managed service — Neon is doing a lot of infrastructure work behind the scenes. But I knew what I was actually using out of all of it:
- A PostgreSQL database
- The ability to branch it for development
- The ability to reset branches to a clean state
That's it. I wasn't using serverless scale-to-zero. I wasn't using the HTTP query API. I was paying managed-service rates for a workflow that should, in theory, be possible to self-host. So I went looking.
What I actually needed from Neon
Before diving into alternatives, I had to be honest about which Neon feature I was paying for. Neon does a lot of things — serverless connection pooling, autoscaling compute, pay-per-second billing, a custom storage engine. Most of that is infrastructure complexity I don't need.
The feature I couldn't live without was this: I have a production database. I create a dev branch from it — instantly, regardless of database size. My dev environment connects to the branch instead of production. I break things, run migrations, and mess with data freely. Then I reset back to the production baseline whenever I want.
Once you've had that workflow, sharing a single staging database with your team feels like going back to FTP deploys. The question was whether there's an open-source way to get exactly this on my own VPS.
Enter DBLab
The answer turned out to be DBLab (Database Lab Engine), an open-source tool from postgres.ai.
DBLab does one thing: instant PostgreSQL cloning using ZFS thin provisioning.
It runs as a Docker container on your VPS. It uses ZFS — a filesystem with built-in copy-on-write snapshotting — to create thin clones of your PostgreSQL data directory. A thin clone shares all the underlying data blocks with the original snapshot and only stores what changes. Creating a clone of a 100 GB database takes the same 1–2 seconds as cloning a 100 MB one. No full copy. No waiting. Just a new, running PostgreSQL instance that looks exactly like production.
The mental model that makes it click
The most important thing to understand about DBLab is this: it is a photocopier, not a proxy.
Your production database keeps running exactly as it always has. Your app keeps connecting to it directly. DBLab is not in the production path. It doesn't sit between your app and your database. It doesn't touch production writes.
PRODUCTION
Your App → prod PostgreSQL (Neon / Supabase / RDS / self-hosted)
│
└── pg_dump (read-only, one-way copy)
│
▼
DBLAB (your VPS)
snapshot of prod data (ZFS)
│
├── clone → developer A (port 6000)
├── clone → developer B (port 6001)
└── clone → CI pipeline (port 6002)
DBLab pulls a read-only copy of your production data — once, or on a schedule. After that, it works entirely from the local copy. There is no ongoing connection back to production. Production doesn't know DBLab exists.
The worst thing that can happen on a DBLab clone — dropping every table, corrupting data, running a catastrophic migration — affects only that clone. You reset it in one second. Production is untouched.
The vocabulary of branching
If you're coming from Git, these terms feel familiar, but they work slightly differently when you're talking about gigabytes of raw database files. Here is how DBLab and ZFS think about them.
A snapshot is a static, read-only photo of your data at a specific moment. It takes up almost zero space because it just marks which blocks of data existed at that time. You cannot connect to a snapshot from your app.
A branch is a logical pointer. When you create a dev branch, you're naming a snapshot so you can find it later.
A clone is the actual running database — the living thing. When you create a clone, DBLab takes a snapshot and makes a thin copy of it that you can connect to and write to. This is where you run your migrations.
| Term | What it is | Writable? | Analogy |
|---|---|---|---|
| Snapshot | Point-in-time data | ❌ No | A photo |
| Branch | A named reference | ❌ No | A Git tag |
| Clone | A running process | ✅ Yes | A photocopy |
What a real dev morning looks like
I run Payload CMS with Next.js. Here's my actual daily workflow now.
# 1. Create a clone from the dev branch — takes ~2 seconds
dblab clone create --branch dev --id matija --username appuser --password secret
# → DBLab returns: host=my-vps port=6000
That connection string goes straight into my local environment:
DATABASE_URI=postgres://appuser:secret@my-vps:6000/mydb
My app starts locally and connects to the DBLab clone — which has real production data, real schema, real content. Not seed data. Not a months-old staging copy. Actual prod.
# Test a Payload migration against real production data
payload migrate
# Something broke? Reset to baseline in 1 second
dblab clone reset matija
# Works? Run it on prod with confidence
payload migrate --env production
That last step is the entire point. Running the migration on production after proving it works on a clone with real prod data means no more "it worked on my machine with seed data."
How connection strings work
When you create a clone, DBLab spins up a real PostgreSQL container, assigns it a port from a pool (6000–6099 by default), and gives you a connection string. You put that in .env.local. Your dev app connects to it like any other PostgreSQL.
| Environment | Who issues the string | Example |
|---|---|---|
| Production | Your DB host (Neon, Supabase, RDS) | postgres://user:pass@prod-host:5432/mydb |
| Development | DBLab, when you create a clone | postgres://appuser:secret@your-vps:6000/mydb |
Each developer gets their own clone on their own port. No shared dev database. No stepping on each other's changes.
| Developer | Clone ID | Port |
|---|---|---|
| Alice | alice-dev | 6000 |
| Bob | bob-dev | 6001 |
| CI job #123 | ci-pr-123 | 6002 |
Each clone is independent, disposable, and costs almost no extra disk space thanks to ZFS copy-on-write.
Why this beats a shared staging database
Before DBLab, the standard answer was "use a staging database." Here's why that never actually worked well.
| Staging DB | DBLab clone | |
|---|---|---|
| Shared across team | Yes — one person's migration breaks everyone | No — one per developer |
| Reset to prod state | Manual, coordinated, often forgotten | 1 second, any time, self-service |
| Creation time | Days of setup and coordination | 2 seconds |
| Drift from production | Constant — staging gets stale fast | Zero — always based on latest snapshot |
| Cost model | Always running, always drifting | Exists only when needed |
The honest comparison: Neon vs. self-hosted DBLab
DBLab doesn't replace everything Neon does. Neon is a managed database platform doing a lot more than branching. Here's the honest picture:
| Feature | Neon | DBLab (self-hosted) |
|---|---|---|
| Database branching | ✅ Built-in | ✅ Via ZFS snapshots |
| Instant clone/reset | ✅ | ✅ |
| Serverless scale-to-zero | ✅ | ❌ Not applicable |
| HTTP query API | ✅ | ❌ |
| Connection pooling | ✅ Built-in (PgBouncer) | ❌ Add your own |
| Pay-per-second billing | ✅ | ❌ Fixed VPS cost |
| Zero infrastructure management | ✅ | ❌ You manage it |
| Data stays on your infra | ❌ Neon's cloud | ✅ Your VPS |
| Monthly cost (my usage) | €40–60+ and growing | ~€5 fixed (Hetzner VPS) |
| Open source, self-hostable | Partially (not practical) | ✅ Fully |
If you need serverless PostgreSQL, Neon is still the right tool. If what you actually use is the branch-and-reset workflow — and you want it on your own infrastructure with predictable costs — DBLab is the open-source answer.
What it runs on
Everything runs in Docker on a single VPS:
| Container | Role |
|---|---|
postgresai/dblab-server | The engine — manages ZFS snapshots, branches, clones |
postgresai/ce-ui | Web UI for managing clones in a browser |
postgresai/extended-postgres:17 | Spun up per clone, destroyed when done |
nginx | Reverse proxy for the UI |
The only host-level requirement is ZFS, which ships in the standard Ubuntu 24 package repository. Everything else is containerized.
The setup at a glance
I won't walk through every step here — the full setup guide is in the repo — but the high-level flow is:
- Get a VPS — Ubuntu 24, Docker installed, a spare disk or partition for ZFS
- Install ZFS —
apt install zfsutils-linux, create a pool - Configure the source — Point DBLab at your production PostgreSQL via connection string in
.env - Start the engine —
make up— it pulls a logical dump from your source automatically - Create branches —
dblab branch create main, thendblab branch create --parent-branch main dev - Create clones —
dblab clone create --branch dev --id my-clone --username appuser --password secret
From that point on, clones are created in seconds, reset in seconds, and production is never touched.
# The full lifecycle in 30 seconds
dblab clone create --branch dev --id test --username dev --password dev
# → port 6000, connect your app
dblab clone reset test
# → back to clean state, 1 second
dblab clone destroy test
# → gone, resources freed
What I gave up (and what I didn't miss)
Switching from Neon to DBLab meant giving up zero infrastructure management — I now maintain a VPS. In practice, that's one Docker Compose file and a ZFS pool. It took an afternoon to set up and hasn't needed attention since.
I also gave up serverless scaling, but my production database still runs on its managed host. DBLab is only for the dev and test clones, which don't need autoscaling. And yes, I gave up the Neon dashboard — DBLab has its own web UI. It's simpler, but it does what I need.
What I gained is predictable costs. €5/month for a Hetzner VPS instead of €60+/month and climbing. My production data copy lives on my VPS rather than transiting through a third-party branching service. And there's no vendor lock-in — it's standard PostgreSQL on standard ZFS. If DBLab disappeared tomorrow, the data is still there in a ZFS dataset.
FAQ
Does DBLab work with any PostgreSQL host, or only Neon? It works with any PostgreSQL host — Supabase, RDS, self-hosted, or Neon itself. DBLab only needs a connection string to pull the initial logical dump. What your production database runs on is irrelevant to DBLab.
How fresh is the data in my clone? As fresh as your last sync. You configure the sync schedule in the DBLab config — hourly, daily, or on-demand. Most workflows are fine with a nightly sync.
Can multiple developers use the same DBLab instance? Yes. Each developer creates their own named clone and gets their own port. The clones are fully isolated — one developer's migrations don't affect anyone else's clone.
What happens if I run out of ports? The default pool is 6000–6099, giving you 100 simultaneous clones. You can expand the range in the config. Realistically, clones should be destroyed after use, so you'd rarely approach that limit.
Is ZFS hard to manage? For this use case, no. You create the pool once during setup and DBLab manages everything inside it. You don't need to understand ZFS internals — just that it exists and powers the instant cloning.
The bottom line
The feature that made Neon feel magical — instant database branching with real production data — is available as open-source software on a €5/month Hetzner VPS. You just have to set it up yourself.
For me, that trade-off was worth it the month I saved €55. Every month since has been a bonus.
If you're running into the same Neon billing curve and want to try this, check out the DBLab documentation to get started. Drop me a message if you get stuck — I've hit every gotcha so you don't have to.
Thanks, Matija
Frequently Asked Questions
Comments
No comments yet
Be the first to share your thoughts on this post!