Document: WM-097 P. Webb
Category: Tutorial 2026-06-22
How to migrate from Gel to Disc
Abstract
The hardest part is getting your data out of Gel in a useable format,
the rest is easy (but mind your links on the way in, warning near
the end).
Body
Dumping your Gel database to a format other databases can read
requires arcane knowledge but don’t fret, I’ve uncovered the
incantations to free your data!
Perform this full backup, for peace of mind.
gel dump --all --format=dir gel-export
You should see something like:
Connecting to Gel instance 'INSTANCE' at localhost:PORT...
Starting dump for database `'DATABASE'`...
Finished dump for `'DATABASE'`. Total size: 181.67 KiB
This will create gel-export in your current directory. Take note of
the instance and database names and the port as you’ll need these
later. Next, grab the password to your database:
gel instance credentials --insecure-dsn -I INSTANCE
You should see something like:
gel:///DATABASE?port=PORT&password=PASSWORD&tls_ca_file=%3C...%3E&tls_security=no_host_verification
Now we can set some variables to make the last bits pseudo-legible.
sslmode=require because Gel refuses plaintext connections, and
without it psql fails with a misleading auth error before the real
"TLS required" one.
DSN="postgresql://edgedb@localhost:PORT/DATABASE?sslmode=require"
export PGPASSWORD="PASSWORD"
Gel’s binary dump is useless to anything but Gel, so to get tabular
data out we go through its SQL adapter. List the tables into a .tsv
first, without any escaping that could mangle the identifiers:
psql "$DSN" -At -F $'\t' -c "
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'pg_catalog')
" > gel-export/tables.tsv
Create our final export directory:
mkdir gel-export/data
Finally, we render our .csvs:
while IFS=$'\t' read -r schema table; do
out="${schema}_${table}"
psql "$DSN" --csv -c "SELECT * FROM \"$schema\".\"$table\"" > "gel-export/data/$out.csv"
done < gel-export/tables.tsv
A quick note on what’s in those CSVs, because it bites at import
time (and it bit me)!
Gel maps each object type to a table with id and __type__
columns, single properties as plain columns, and (what got me) single
LINKS as <link>_id UUID columns (your owner link becomes an
owner_id column holding the target’s id).
Multi links and multi properties aren’t in these tables at all; they
live in their own source/target tables and import as
separate files.
I’ll assume you installed Disc[1] already. Great! You’ll need to get
it setup with your schema. Run that migration!
disc migrate
Next, we’ll point Disc at your fresh collection of .csvs:
disc db import ./gel-export/data
This SHOULD work; it didn’t for me because…
✗ Import failed (transaction rolled back): duplicate key value violates unique constraint "log_pkey"
…and that’s irrelevant to me. Ignoring conflicts like this is okay.
disc db import ./gel-export/data --on-conflict skip
You’ll get an import manifest of what was processed and skipped.
Remember those <link>_id columns? Disc resolves them into your
single links, but anything it can’t map surfaces here as a warning.
Confirm your links got set and that no non-empty column was
quietly discarded.
A previous version of Disc silently dropped every <link>_id column
and because I’m dogfooding this, I found the issue and fixed. This is
bleeding edge folks!
Run disc serve and navigate to your database’s /ui and you should
see populated objects in the Data tab.
Voila! Now all you gotta do is update your codebase…unfortunately,
you’ve gotta handle that yourself. 🕸️