You want to move your Airtable Bases to SeaTable and are afraid of the effort? Don't worry! Even bases with complicated data structures and many thousands of records can be transferred to SeaTable with little effort.
For the transfer of Airtable data into SeaTable we have developed a migration script. It transfers all data of an Airtable base - tables, columns, records - in one go to a SeaTable base. After the migration you can continue in SeaTable with the data you used last in Airtable. After execution of the script only minor rework is necessary.
The script can be used by everyone - technicians as well as non-technicians. However, due to limitations on the part of the Airtable API, the procedure is unfortunately not highly automated. Some manual specifications are required to make the script operational. In this article we explain how to do that.
How to migrate a Base from Airtable to SeaTable
1. create base
Create a new base in SeaTable. The name of the SeaTable Base does not have to be the same as the name of the Airtable Base you want to import. You can choose the name freely.
2. insert script
Open the script management in the new Base by clicking on the script icon in the Base header in the upper right corner. Then select Add Script. The migration script is written in the Python programming language. Therefore, select Python.
airtable_api_key
simply such a Personal Access Token in. This person must have the authorization data.records:read
have.Now select the following code block, copy it to the clipboard and then paste it into the left window of the script editor:
## Parameterize the script # SeaTable - Destination server_url = 'https://cloud.seatable.io' api_token = '...' # Add the API token of the SeaTable base # See https://seatable.io/docs/en/seatable-api/erzeugen-eines-api-tokens/ # for more information on how to create a SeaTable API token # Airtable - Source airtable_api_key = '...' # Add the API key of the Airtable base # See https://support.airtable.com/docs/creating-and-using-api-keys-and-access-tokens/ # for more information on how to create an Airtable API key airtable_base_id = '...' # Add the base_id of the Airtable base # See https://support.airtable.com/docs/finding-airtable-ids/ # for more information on where to find the id of an Airtable base table_names = ['...', '...'] # Add the names of all tables in the Airtable base, i.e. ['table 1', 'table 2'] # The names must be enclosed in '' and comma-separated first_columns = [ ('...', '...'), ('...', '...'), ] # Specify the names of the first columns in every table of the Airtable base # Use the format ('table_name', 'first_column_name'), i.e. ('table 1', 'ID') # The table and column name must be enclosed in '' and comma-separated links = [ ] # Specify the links between the tables in the Airtable base # Use the format ('table_name', 'column_name', 'other_table_name'), i.e., ('table 1', 'link to table 2', 'table 2') # The table and column names must be enclosed in '' and comma-separated # If the Airtable base contains no link columns, just leave the brackets empty mode = 'import-header' # Specify the run-mode of the script, two options: 'import-header' and 'import-rows' # Run 'import-header' first to create the data structure in the SeaTable base # Run 'import-rows' to import all the rows ## No more edits required beyond this row import sys from seatable_api import Base, AirtableConvertor # from airtable_importer_settings import server_url, api_token, # airtable_api_key, airtable_base_id, table_names, first_columns, links def get_convertor(): base = Base(api_token, server_url) base.auth() convertor = AirtableConvertor( airtable_api_key=airtable_api_key, airtable_base_id=airtable_base_id, base=base, table_names=table_names, first_columns=first_columns, links=links, ) return convertor def import_header(): convertor = get_convertor() convertor.convert_metadata() def import_rows(): convertor = get_convertor() convertor.convert_data() if mode == 'import-header': import_header() elif mode == 'import-rows': import_rows() else: print('The mode is not properly specified.') ## End script ##
Don't worry if you don't understand the code. We will explain it. The comments in the code should help a little with interpretation. Comments are all rows with leading hash sign ('#'). These rows are ignored during script execution, i.e. you can change the comments and add more.
Unlike the comments, the indentations in the code are very important when running the script. Please do not change them.
3. specify SeaTable server URL and API token of the base.
Under the comment SeaTable - Destination, add the SeaTable server URL and specify the API token. If you are using SeaTable Cloud, then the pre-filled URL "https://cloud.seatable.io" is correct. If you are using a different SeaTable server, then enter its URL. (The URL must always be entered with https:// or http://.) The URL and token must be enclosed in single quotes.
This is a sample configuration when using SeaTable Cloud:
4. enter Airtable API key and Base ID
Under the comment Airtable - Source add the Airtable API key as well as the Airtable Base ID, both values again in single quotes.
This is how it should look then:
5. enter table and column names
Now tell the script which tables you want to import. Do this in the row "table_names". In the square brackets, add the names of the tables in the airtable base - each enclosed by a single quote and separated by commas.
For a base with two tables "table 1" and "table 2", the row must then look like this, for example:
If your airtable base has more than two tables, simply extend the enumeration in the parenthesis.
Due to a limitation of the Airtable API, you must also specify the names of the first columns in the tables. This is done in the row "first_columns" or the following rows.
For the airtable base with the two tables "table 1" and "table 2" it could then look like this:
6. define link columns
In order for SeaTable to import the data properly, one more step is required: specifying the link columns in Airtable Base.
The row "links" is intended for this purpose. For example, if the column "link to table 2" in the table "table 1" maps a link to the table "table 2", then the script should be parameterized as follows:
You need to specify each link column pair only once. You do not need to specify the link in both directions.
If the airtable base does not receive any link columns, then you can leave the square bracket empty:
7. import tables and columns
The script can be executed in two modes: "import-header" and "import-rows". First, the script must always be executed in the "import-header" mode. In this mode, the tables and columns are created in SeaTable Base and 10 test rows are imported.
The execution mode is set in the row of the same name:
Now run the script by clicking Run Script. During the execution you can see the executed steps on the right side in the editor. In the background you can also see how the tables and columns are created.
8. check test lines
Now check whether
- all tables and all columns have been imported,
- the correct first row was created in all tables and
- the link columns are correct.
Since the column types of Airtable and SeaTable are not completely congruent, some column types in SeaTable Base will differ from those in Airtable Base. The following table shows how the column types in Airtable are transferred to SeaTable.
Airtable column type | Import to SeaTable column type |
---|---|
Attachment | File |
Autonumber | Number (conversion to a car number column possible) |
Barcode | Text or number |
Button | - (no migration possible) |
Checkbox | Checkbox |
Count | Number |
Created time | Date |
Currency | Number |
Date | Date |
Duration | Number (conversion to a column of type duration possible) |
Formula | Date, text or number |
Last modified by | Text |
Last modified time | Date |
Link to another record | Link to other entries |
Long text | Formatted text |
Lookup | Date, text or number |
Multiple select | Multiple selection (No migration of unused options) |
Number | Number |
Percent | Number |
Phone number | Text or number |
Rating | Number (conversion to a column of type Rating possible) |
Rollup | Date, text or number |
Single line text | Text |
Single select | Text (conversion to a single selection column possible) |
User | Text |
URL | Text |
If something is not right, then check the inputs in steps 5. and 6. and run the script again in import-header mode.
9. import all records
If the verification in step 8. is to your satisfaction, then all records can be transferred.
In the script, change the mode from "import-header" to "import-rows":
Run the script again by clicking Run Script. Again you can watch the execution of the script on the right side and see the activities in the background.
Now you should see all records from the Airtable Base in the new SeaTable Base. Congratulations, the dataset migration is complete!
If you are not satisfied with the final result, delete all tables and start again at step 7.
10. complete migration
The migration script has transferred all data. Some manual rework may still be necessary now.
The migration script does not transfer formula columns as formula columns, but creates text columns and inserts the formula results into them. I.e. you still have to add formula columns manually in the SeaTable Base. The same applies to columns of type Count, Lookup and Rollup. Button columns are not transferred at all.
Since the order of the columns cannot be retrieved via the Airtable API, this information is unfortunately not available when creating the columns in SeaTable. If you want to restore the original order, then you have to do it manually.
Views from the Airtable Base are not transferred. You must create views yourself.
FAQ area
Does the script change data in my airtable base?
No. The script only reads your airtable base. The data in the airtable base is not changed.
What do I do if I receive an error message?
An error message at the first execution is not unlikely at all. There are enough reasons for this, e.g. a wrong API token, the incorrect order of links, typos, missing commas and incorrect indentation. A single error can cause the script execution to abort.
If you receive an error message, then this is basically not a problem. Data cannot be lost. Proceed as follows:
- In most cases, the error message will give you a hint where to find the error. Follow it, correct the entered parameters and run the script again. An indentation error, for example, indicates that the indentation does not conform to Python syntax.
- If the error message is incomprehensible, check all entries for correctness and try again.
- If none of the tips help, get help in the SeaTable Forum.
Can columns in the airtable base be overlooked?
Yes, this can happen with columns that contain only a few entries. In the "import-header" mode the script checks the first 100 rows of the airtable base. If a column does not contain an entry in these rows , the Airtable API does not return this column and the corresponding column is not created in SeaTable. Consequently, it will not be included in the migration of all records.
Can Airtable Bases of any size be migrated?
In principle, yes. However, the procedure presented in this article with the integrated Python editor is subject to a maximum runtime limit of 15 minutes, i.e. scripts that run for longer than 15 minutes are aborted. In practice, this is sufficient for the vast majority of bases. For bases with large/many file attachments, however, this limit can play a role.
Is it possible to import tables into an existing base?
The script does not require a base to be empty. So you can run the script even in a base with existing, filled tables. The only thing you should avoid is duplicating table names.