Look, I’m gonna be honest with you. I was supposed to be working on my startup. I had a 9–5. Life was busy. But then this one thing kept annoying me SO much that I had to stop everything and fix it.
You know that moment when you’re deep in a feature branch, you’ve run your migrations, everything’s working perfectly, and then you need to switch back to main for a quick hotfix?
And then your app just… explodes.
Your database is completely out of sync. The schema doesn’t match the code. ActiveRecord is screaming at you. Rails can’t find the user_preferences table that doesn’t exist yet on main. Nothing works.
We’ve all been there. And the “solutions” are genuinely terrible:
Drop the database and re-seed; Cool, let me just wait 5 minutes while I lose all my test data
Manually roll back migrations; Hope you remember exactly which ones to undo and in what order
Maintain multiple databases; And constantly remember to switch your connection string. No comments here
None of these are good. And I was tired of it.
The “Wait, PostgreSQL Can Do WHAT?” Moment
So I’m procrastinating one evening (typical dev chores, while Claude is running), reading PostgreSQL docs instead of working on my actual startup, and I stumble upon this:
CREATE DATABASE new_db TEMPLATE source_db
Joking, I recall we used this at work for tests. But the procrastination piece sounds better imo.
Template databases. PostgreSQL can create a database from another database as a template. And here’s the wild part — it’s a file-level copy. It’s not doing some expensive pg_dump and restore. It’s just copying the data files.
It’s fast. Like, really fast.
And my brain immediately went: “Wait. What if I could just… snapshot my database on each git branch? And switch between them instantly?”
After 1 minute of googling for existing solutions, I decided I needed to build this.
Building the Thing
The core idea is stupidly simple. When you run pgbranch branch main, it creates a database called myapp_dev_pgbranch_main using your working database as a template. That’s your snapshot.
When you run pgbranch checkout main, it drops your working database and recreates it from the snapshot.
No pg_dump. No restore. No waiting.
pgbranch init -d myapp_dev
pgbranch branch main # snapshot your clean main state
... switch to feature branch, run migrations, break things ...
pgbranch branch feature-x # save this state too
pgbranch checkout main # instantly back to clean state
I wrote the whole thing in Go because, honestly, CLI tools in Go just feel right. Single binary, cross-platform, fast startup time. No “installing dependencies” nonsense. (I just don’t know Rust)
The architecture is pretty clean. There’s a Brancher core that handles the business logic, a postgres.Client that talks to PostgreSQL using pgx (the best Go postgres driver, fight me), and a CLI layer using Cobra.
The Gotcha That Almost Broke Me
Here’s something I learned the hard way: you can’t create a database from a template if there are active connections to the source database.
PostgreSQL will just say “nope, database is being accessed by other users” and refuse to cooperate.
So every operation that touches a database needs to first terminate all connections:
func (c *Client) TerminateConnectionsTo(dbName string) error {
_, _ = conn.Exec(ctx, `
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = $1 AND pid <> pg_backend_pid()
`, dbName)
return nil
}
It’s one of those things that seems obvious in retrospect but had me debugging for way too long.
Scope Creep (But Like, The Good Kind)
Okay, so I had the basic branching working. Cool. Ship it. Done.
But then a guy on Reddit asked… what if it could automatically switch database branches when you switch git branches?
Git has these things called hooks. Specifically, there’s a post-checkout hook that runs after every git checkout. So I wrote a little shell script that:
- Checks if you’re in a pgbranch-initialized directory
- Gets the current git branch name
- Checks if a pgbranch branch with that name exists If yes, checks it out. If no, creates it.
pgbranch hook install
git checkout feature-x # automatically switches database branch too
Now your database just… follows your git branches. Automatically. No thinking required.
But Wait, There’s More
Then I thought about teams. What if you want to share a database snapshot with a colleague? Or spin up a known-good database state in CI?
So I added remotes. Like git remotes, but for database snapshots.
pgbranch remote add origin s3://my-bucket/pgbranch
pgbranch push main --description "Clean schema with seed data"
# On another machine:
pgbranch pull main
It supports S3, Cloudflare R2 (which is S3-compatible so that was easy), and plain filesystem paths for network drives.
The archive format is a gzipped tar containing a manifest (JSON with metadata, checksums, pg_dump version) and the actual pg_dump output in custom format. Checksums verify integrity because nobody wants to restore a corrupted database.
And yes, credentials are encrypted before being stored locally. Because storing AWS keys in plaintext in a JSON file would not be ok.
The Part Where I Get Sentimental
Here’s the thing. I wasn’t building this to get famous or make money. I was building it because the problem annoyed me, and solving problems is fun.
I pushed it to GitHub, posted it on Reddit, and went back to my startup stuff.
Then the stars started coming in.
33 stars in the first week. From real developers. People I don’t know. People who apparently had the same pain point and were excited that someone finally solved it.
And look, 33 stars isn’t going viral. It’s not hitting the front page of Hacker News. But you know what it is?
It’s 33 developers who found something I built useful.
That hit different.
Working on a startup is great. Getting paid at my 9–5 is great. But there’s something special about building something in your spare time, giving it away for free, and watching people actually use it.
It reminded me why I got into programming in the first place. Not for the career. Not for the money. But because building things is genuinely, deeply satisfying.
The Takeaway
Sometimes the best projects come from scratching your own itch. You don’t need a business plan. You don’t need to validate the market. You just need a problem that annoys you enough to fix it.
And if you’re working on migrations across git branches and dealing with the database sync nightmare… maybe give pgbranch a shot.
go install github.com/le-vlad/pgbranch/cmd/pgbranch@latest
It’s free. It’s open source. And if it saves you even one “drop database, re-seed, wait 5 minutes” cycle, I’ll consider it a win.
Now if you’ll excuse me, I have a startup to get back to.
pgbranch: https://github.com/le-vlad/pgbranch
Top comments (0)