← All case studies Heroku Postgres → Neon

DEV moved production Postgres from Heroku to Neon with Bucardo

The DEV team kept the app on Heroku and moved the primary database after more than eight years. Bucardo ran on a DigitalOcean droplet. Leftover triggers forced a restart, and pooling took a few days. They disclose a Neon sponsorship on the same post.

The DEV team published this on DEV on 19 June 2025. It is first-party. The app stays on Heroku. Only the primary production database moved, after more than eight years. They also say the work ended in a Diamond Sponsorship on DEV and better deals for DEV++ members. Peter Kim Frank thanks the Neon team in the comments. I am treating the sponsorship as part of the story, not a footnote you can ignore while reading the cost claim.

DEV and Forem still run on Postgres. The page says the site serves millions of developers a month. Postgres had been the largest single infrastructure expense, ahead of compute. They did not want a cheaper database that was worse to operate. The Heroku → Neon playbook is a backup and pg_restore, and it notes that Neon’s import assistant refuses Heroku. This post did not use that path. They replicated with Bucardo.

What Heroku Postgres would not flex

Heroku Postgres had taken them from a small app to this one. The friction they list is operational.

Production-like databases were hard to stand up. Read replicas were limited and finicky. A traditional instance scaled storage and compute together, and they had little say in how that was billed. They expected more databases, and they wanted autoscaling.

They say they researched a bunch of options and talked to several possible partners before Neon. The post does not name the others. Branching is the developer-experience claim. An isolated database from production data, for a migration, a schema change, or a preview that touches rows, without a shared staging bottleneck. Replicas got cheaper to create, so long queries, automation, and feature-specific read paths could move off the primary. Storage and compute are separate, so they pay for each. Extensions they want later, and are not using yet, include pgvector and pg_search, plus the Neon Data API. Ben Halpern’s reply on the post, when asked about semantic search, is “probably”. That is not a shipped feature.

The cost line is “a good chunk” of the database bill. No dollar amount, no percentage.

Bucardo on a droplet, then a restart

They wanted no data loss and as little downtime as they could get. Bucardo is asynchronous Postgres replication. Triggers on the source record changes. A separate process replays them on the target. They ran Bucardo on a DigitalOcean droplet, with the Neon team, so the replicator sat near both Heroku and Neon and did not run inside the app.

He calls the happy path reliable and the edges finicky. Leftover triggers caused trouble and they restarted the replication once. The post says they finished with virtually no downtime and no data loss. “Virtually” is their word. There is no minute count.

What they did not rehearse was the day after. Years of Heroku defaults had become invisible. Pooling and timeouts on Neon did not match. It took a few days of tuning before performance was where they wanted it. They say they got there.

The app being on Heroku is the split to remember. Connection strings and the database moved. Dynos did not. A reader who follows the playbook’s dump-and-restore steps is doing a different cutover than the one this post describes, and would still have the pooling week this team hit at the end.

Comments on the post are not results. One reader asks about platforms versus consistency. Another says they run Neon on a different site. None of that is DEV’s migration.