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.
```sh
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:
```sh
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.
```sh
DSN="postgresql://edgedb@localhost:PORT/DATABASE?sslmode=require"
```
```sh
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:
```sh
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:
```sh
mkdir gel-export/data
```
Finally, we render our `.csv`s:
```sh
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 `_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!
```sh
disc migrate
```
Next, we'll point Disc at your fresh collection of `.csv`s:
```sh
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.
```sh
disc db import ./gel-export/data --on-conflict skip
```
---
You'll get an import manifest of what was processed and skipped.
Remember those `_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 `_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. 🕸️
References
[1]