Skip to main content
Skip to main content

Neon-style Postgres branching on your own infrastructure

PostgresDatabaseDevOpsSOC2Open SourceDeveloper ExperienceNeonPreview EnvironmentsCI/CD
Amir Angel, Software Developer
Aug 18th, 20267 min read

Once you've had per-branch preview databases, going back feels like losing a limb. You open a PR and a fresh, isolated database shows up seeded with real-looking data. Migrations run against it. You click a preview URL and poke at the actual feature instead of imagining it. Nobody's clobbering a shared staging DB, nobody's waiting their turn, and "works on my machine" stops being a sentence anyone says.

We had every bit of that with Neon. Then we tore it out anyway. This is the story of why, and what we replaced it with.

The good part

I want to be clear before I say anything critical: Neon is a genuinely excellent product. Their copy-on-write branching makes a new branch feel instant and costs almost nothing in storage, and the GitHub integration just works — no fiddling. For the better part of a year it did exactly what we needed and I recommended it to people. If cost and compliance aren't pressing on you the way they ended up pressing on us, honestly, go use Neon. It's good.

But two things crept up on us.

Problem one: the bill

Neon prices by compute-hour and storage GB. Reads cheap on the pricing page. Reads a lot less cheap on the invoice.

The per-unit cost was never really the problem — the problem was how engineers actually behave. Preview branches linger. Somebody opens a PR, gets yanked onto an incident, and three weeks later that branch is still sitting there, idle compute waking up now and then on a stray health check. Now do that across fifteen engineers, each juggling a few open PRs plus a couple of pet experiment branches they swear they'll close (they won't). We were parked around $800/month. Then one month it sailed past a thousand — a pile of data-heavy branches nobody had cleaned up (I know, we should've automated teardown months earlier) — and at 3pm on a Friday Matan dropped a message in our infra channel: "wait, why are we paying a SaaS for this at all?"

Bar chart of Neon compute bills across Q1 to Q3 2024: $620, $810, and a highlighted $1,040

Nobody had a good answer. We already run our own managed Postgres, and that box costs the same whether it's hosting three databases or thirty.

Problem two: compliance

The money stung. This part kept me up more.

Side-by-side architecture: with Neon, data leaves your VPC to an external cloud; with TenDB, everything stays inside your VPC on your own Postgres

We were partway through a SOC2 Type II audit in Q2 2024 when our security lead, Tal, started asking about Neon — the kind of questions you can't hand-wave through. Every third-party SaaS that touches our data is a sub-processor. That means enumerating it, getting agreements signed, and being able to say exactly where the data physically lives. And preview databases are sneakier than they look: dev and staging schemas mirror production, and they get seeded from snapshots that are sanitized, sure, but sanitized-ish. All of that was walking out of our infrastructure and landing on somebody else's servers.

Right as this was happening, enterprise prospects started asking the same thing in their vendor questionnaires — who are your sub-processors, and where does our data go? Try writing "a serverless Postgres provider we use for preview environments" on that line when your own Postgres already sits comfortably inside your compliance boundary. It's not a fun line to write. It's a worse one to defend on a call.

What we actually wanted

Nothing fancy. A short list:

  • Reuse the Postgres box we already pay for and already audit.
  • One fresh, isolated database per branch, named after the branch.
  • Migrations run automatically, with an optional snapshot restore for realistic data.
  • Everything torn down when the PR closes.
  • A GitHub Actions hookup that fits in a few lines.
  • No third-party account, no billing surprise, no new sub-processor to explain.

We went looking for something off the shelf that did this against a server we already ran. Came up empty. So we wrote it ourselves and open-sourced it.

TenDB

TenDB is a small CLI — plus an optional server — that you aim at your existing Postgres. It doesn't provision anything or spin up infrastructure. It just creates and drops databases on a box you already control.

Using it is deliberately dull:

# Point it at your Postgres once
export TENDB_ADMIN_URL="postgres://admin@db.internal:5432/postgres"

# Create an isolated DB for the current branch, run migrations, seed it
tendb up --branch "$GIT_BRANCH" --migrate --seed-from staging

# ... your tests / preview env run against it ...

# Clean up when you're done
tendb down --branch "$GIT_BRANCH"

tendb up spins up a clean database named for the branch (say, pr_feature_upload_photo), runs your migrations, and can pull a snapshot off staging so reviewers land on realistic data instead of a wall of empty tables. tendb down drops the whole thing.

Wire it into CI and it mostly disappears into the background:

# .github/workflows/preview-db.yml
name: Preview DB
on:
  pull_request:
    types: [opened, reopened, synchronize, closed]

jobs:
  preview-db:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Provision preview database
        if: github.event.action != 'closed'
        run: npx @10play/tendb up --branch "pr-${{ github.event.number }}" --migrate --seed-from staging
        env:
          TENDB_ADMIN_URL: ${{ secrets.TENDB_ADMIN_URL }}

      - name: Tear down on merge/close
        if: github.event.action == 'closed'
        run: npx @10play/tendb down --branch "pr-${{ github.event.number }}"
        env:
          TENDB_ADMIN_URL: ${{ secrets.TENDB_ADMIN_URL }}

PR lifecycle flow: Open PR, tendb up (branch pr-142), run migrations, seed from staging, review and test, merge, tendb down

Open a PR, a database appears. Merge or close it, the database is gone. The only secret in play is an admin connection string pointing at a server that already lives inside your network.

The result

  • No extra infra bill. The Postgres box was already on the books; now it does one more useful job. That ~$800/month line vanished.
  • Data stays put. Nothing new to add to the sub-processor list, nothing new to reason about for residency, and a clean, one-word answer when the questionnaires show up.
  • Engineers didn't notice a downgrade. Fresh isolated database in seconds, same as before — only the address changed.

The honest trade-off

TenDB isn't a Neon replacement for everybody, and I'd rather say so plainly. You have to run your own Postgres. If you're all-in on serverless and never want to babysit a database, Neon's managed compute and copy-on-write branching are real advantages we make no attempt to match — we're creating and dropping ordinary databases on your machine, so a genuinely huge snapshot costs genuine disk and genuine restore time. Wanting to avoid operating Postgres in the first place is a completely valid reason to stay on Neon; TenDB just hands that job back to you.

For us it wasn't a hard call. We already ran the server, and the compliance angle would've justified the move on its own. Your math might land somewhere else, and that's completely fine.

Try it

TenDB is open source, MIT licensed.

If you're paying a third party for per-branch databases and squinting at a bill — or a vendor questionnaire — you didn't see coming, take it for a spin. And when you do, .

You might also like