The post lives at mostviertel.tech, under /blog/2024/. The page itself prints no day. The site footer links GitHub user kitsunekyo. The author used PlanetScale for hobby projects. When the free plan went away, they picked Neon.
Sam Lambert’s post on 6 March 2024 is the announcement they link. PlanetScale retired the Hobby plan on 8 April 2024. The author says Neon’s free tier fit, and that the Launch plan started at $19, which looked more reasonable if a hobby project had to grow. That $19 is the price in the post. CockroachDB is the other option they mention and do not use.
The PlanetScale → Neon playbook is pgloader, a direct Neon connection, and the endpoint id inside the password. This write-up is that path, plus Prisma. There is no row count and no downtime figure.
pgloader, built from source
brew on an M1 Mac failed. apt install on Ubuntu 22.04.4 failed. They cloned pgloader and built it with SBCL.
PlanetScale had two branches, main and dev. Each got a .load file. The load they publish looks like this, with the passwords already redacted in the original:
load database
from mysql://<USER>:<PASSWORD>@aws.connect.psdb.cloud/mydb?sslmode=require
into postgresql://<USER>:endpoint=ep-super-paper-12345;<PASSWORD>@ep-super-paper-12345.eu-central-1.aws.neon.tech/mydb?sslmode=require
with quote identifiers, include drop, create tables, create indexes
alter schema 'mydb' rename to 'public'
;
The file has to end with a semicolon. include drop drops tables on the Neon side. They say to point it at the right database and to back up anything already there.
Neon’s MySQL guide uses the same password trick. pgloader wants endpoint=<endpoint-id>; in front of the password. The sample host in the post is eu-central-1. The current Neon page also says to install pgloader with Homebrew on an ARM Mac. This author says brew failed on an M1, which is why they compiled it.
Read the MySQL query string twice. An earlier snippet on the page uses sslaccept=strict, which is what PlanetScale’s normal URL uses. The prose then says to change sslmode=require into sslaccept=strict. The .load file they paste still has sslmode=require on the MySQL line. Match the connection string that already works in the PlanetScale dashboard, and keep one parameter name.
Prisma names stay camelCase
quote identifiers keeps the original case. A Prisma model named PasswordResetToken stayed that way, and a column like userId stayed camelCase. Skip the option and pgloader lowercases every name, which means a Prisma schema change.
The flags include drop, create tables, and create indexes are optional. They used them.
The schema edit they show is the datasource provider. The snippet on the page spells it postgressql (three s characters) and leaves relationMode = "prisma". Copy postgresql from Prisma’s docs if you retype that block. They say quote identifiers meant they did not need @@map for table names.
They also put the endpoint= password form into the app’s DATABASE_URL, and into CI secrets. Neon’s pgloader doc shows that form for the load. The post uses it for the running app as well.
The baseline, because PlanetScale migrations would not export
PlanetScale’s Prisma migration history would not come out. Neon expects a _prisma_migrations table. Their repair follows Prisma’s baseline workflow, then a second pass they call hacky.
prisma db pull rewrote the schema with the types actually in the database. A Prisma String had been varchar(191) on PlanetScale’s MySQL. Postgres would rather use text.
They generated a 0_init migration from an empty database to the pulled schema, deleted two junk lines the CLI had printed at the top of migration.sql, and marked it applied with prisma migrate resolve --applied 0_init. They did not run that SQL. The tables were already there.
Removing every @db annotation and every map in one migrate dev made Prisma want to drop all tables. They split the work. First drop @db.VarChar(191) and migrate. Then timestamps. Then the maps. Each step was small enough to keep the data.
When the schema matched the pre-move file, they deleted every row in _prisma_migrations, deleted the local migrations folder, and baselined again from that cleaned schema. Same 0_init, same migrate resolve --applied. They say a new empty database and a fresh load might be cleaner. This is what worked on the database they had already filled.
What I would copy
Build pgloader if the packaged binary will not run. That was the first blocker, on both macOS and Ubuntu.
Turn on quote identifiers if Prisma models are camelCase. Budget a schema rewrite if you leave it off.
Put the Neon endpoint id in the pgloader password, and test with sslaccept=strict if that is what PlanetScale already gave you. The pasted .load file and the prose on this page disagree.
Pause on migrate dev if it wants to drop tables. Their safe path was one annotation family at a time, then a second baseline. They also say you might throw the database away and load into a new one instead of editing _prisma_migrations by hand.