nocodb-transfer: copying NocoDB bases between installations

A command line tool that exports a NocoDB base with its links, lookups, rollups, formulas, attachments and views, rebuilds it on another installation and compares both record by record.

The problem

NocoDB is an open source spreadsheet interface over a database, often used as a self-hosted Airtable replacement. It can import from Airtable and can move a self-hosted base to NocoDB Cloud. It cannot move a base from one NocoDB installation to another, or from Cloud back to a self-hosted server. CSV export works per table and loses links, lookups, rollups, formulas and views.

Issue #9596, "Ability to cross copy bases across installations", has been open since October 2024 with 81 reactions and no answer from the maintainers. The comments name three uses: disaster recovery ("Due to the lack of an option to export the database, there is a feeling of insecurity"), leaving the hosted service after a trial, and handing a template base to many other users. One commenter notes that moving to and from Airtable is easier than moving between NocoDB installations. The only related code I found on GitHub, two scripts from December 2025, states in its README that link, lookup and rollup columns are not included.

How nocodb-transfer works

nocodb-transfer is a Python command line tool without dependencies. It uses the public REST API with an API token. export writes a snapshot directory: the table metadata and views as NocoDB returns them, one JSON line per record, the links of each relation, and the attachment files under their SHA-256. import rebuilds a base from it, copy does both, and verify compares two bases.

The import has to follow NocoDB's dependencies. Tables are created with their plain columns first. Every link exists twice in the metadata, once per table, so the tool pairs the two sides (by the foreign key column for has-many and one-to-one, by the junction table for many-to-many), creates the relation once from the parent side and gives the generated reverse column its original title back. Lookups, rollups, formulas, barcode and QR columns follow in dependency order, so a formula over a lookup over a link works. NocoDB stores formulas with internal column ids ({{c5xn...}}); they are rewritten to {Title} before they are created on the target. Then records are inserted in batches of 100 while the tool keeps a map from old to new record ids, because ids differ when the source has deleted rows. Links are created through the links API with that map. Finally the views: filters including nested groups, sorts, hidden fields, kanban grouping, gallery cover and form texts.

Example

This is the CLI copying the test base between two separate local NocoDB 2026.10.1 installations:

$ nocodb-transfer copy --base Fixture1 --title Fixture1 --verify
exported Authors: 256 records
...
exported 5 tables, 306 records, 66 links, 2 files
importing into base Fixture1 (p5molgg1ngzfsnb)
...
imported 66 links
done: base p5molgg1ngzfsnb, 121 API requests
compared 5 tables, 306 records, 6012 values
no differences

How it is tested

verify is also the main test oracle. It compares every field of every record in id order, including the values NocoDB computes on the target: link counts, lookups, rollups and formulas. If a relation were attached to the wrong records, the rollups and lookups would differ. A test changes one value in the target and checks that verify reports it together with the rollup and the formula that depend on it.

The test base has five tables, 17 plain field types, has-many, many-to-many, one-to-one and self links, derived columns that depend on each other, deleted rows, attachments and nine views. The integration tests export it, import it into a second installation and also check view details and attachment bytes. CI runs them between two NocoDB containers, 2026.10.1 and latest, weekly as well. The first CI run found a difference I had not seen locally: the Docker image of NocoDB 2026.10.1 stores one-to-one links on a junction table, while the npm build of the same version I used locally stores them with a foreign key. The tool now pairs both forms, and a unit test holds the metadata from the Docker image. Offline unit tests run on metadata captured from a real installation.

Limits

Users, roles, sharing, webhooks, automations, Button columns, comments, audit history, calendar and map views are not copied. User field values stay empty, and CreatedAt and UpdatedAt get new values. Versions before 2026.10 are untested; building the test base on 0.263.8 failed because its link API rejected the requests. Only bases on NocoDB's default data source were tested, and NocoDB Cloud was not tested at all; the client retries rate limit responses, and on Cloud you would create an empty base in the UI and import into it with --base-id. Densely linked bases need one request per record that has links.

The code is at github.com/Jwrede/nocodb-transfer.