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]