Skip to content

Concepts

Import and export

This page shows how to export a SurrealDB database as SurrealQL with the Python SDK, and how to import SurrealQL into a database. Use export and import to back up a database, to copy data between databases or servers, and to load a prepared dataset.

Method

Description

db.export(options?)

Returns the selected database as SurrealQL text

db.export_to(target, options?)

Writes the export to a file, or to a file object opened in binary mode

db.import_(data)

Imports SurrealQL from a

str

,

bytes

or a file into the selected database

export(), export_to() and import_() work over WebSocket and HTTP connections. Each call sends an HTTP request to the /export or /import endpoint of the server, at the host and port of the connection. The request carries the sign-in, the namespace and the database of the connection's own session, so sign in and call use() first.

An export needs a system user, such as a root, namespace or database user. A record user, or a connection that is not signed in, is refused with HttpStatusError and status 403. Sessions from new_session() do not have these methods.

An embedded connection has no /export or /import endpoint, so the three methods raise UnsupportedFeatureError there. To load SurrealQL into an embedded database, run it through query(), as described in Embedded databases.

export() returns the selected database as one str of SurrealQL:

from surrealdb import Surreal

with Surreal("ws://localhost:8000") as db:
    db.signin({"username": "root", "password": "secret"})
    db.use("surrealdb", "docs")

    dump = db.export()
    print(dump)

For a database that holds only the records person:tobie and person:jaime, the export is:

Output
-- ------------------------------
-- OPTION
-- ------------------------------

OPTION IMPORT;

-- ------------------------------
-- TABLE: person
-- ------------------------------

DEFINE TABLE person TYPE ANY SCHEMALESS PERMISSIONS NONE;




-- ------------------------------
-- TABLE DATA: person
-- ------------------------------

INSERT [ { id: person:jaime, name: 'Jaime' }, { id: person:tobie, name: 'Tobie' } ];

The whole export is held in memory. For a large database, write it to a file with export_to() instead.

Pass ExportOptions to export part of a database. Each field is None by default, which leaves the choice to the server.

FieldWhat it includes
usersThe system users of the database, defined with DEFINE USER
accessesThe access methods, defined with DEFINE ACCESS
paramsThe database parameters, defined with DEFINE PARAM
functionsThe functions, defined with DEFINE FUNCTION
analyzersThe analysers, defined with DEFINE ANALYZER
sequencesThe sequences, defined with DEFINE SEQUENCE
tablesTrue or False for every table, a table name or a list of table names, or {"exclude": [...]} for every table except the ones in the list
recordsThe records of the exported tables
versionsThe earlier versions of each record, from a versioned datastore
from surrealdb import ExportOptions

schema = db.export(ExportOptions(records=False))
people = db.export(ExportOptions(tables=["person"]))
no_posts = db.export(ExportOptions(tables={"exclude": ["post"]}))

schema holds the definitions of the database without its records, people holds only the person table, and no_posts holds every table except post.

Some options depend on the server version:

  • SurrealDB 2.0 does not accept export options. export() with options raises UnsupportedFeatureError there, so call it without options.

  • SurrealDB 2.x servers refuse the {"exclude": [...]} form of tables with HttpStatusError.

  • From SurrealDB 3.3.1, an export holds only the current state of each record. versions=True raises UnsupportedFeatureError against those servers, before the SDK sends the request.

export_to() writes the export as it arrives, so it does not hold the whole export in memory. It takes the path of a file, as a str or a path-like object such as pathlib.Path:

db.export_to("backup.surql")

The SDK replaces a file at that path only when the whole export has arrived. If the export stops before the end, for example because the connection fails, an existing file at the path stays as it was.

export_to() also takes a file object opened in binary mode, and ExportOptions as its second argument:

import io

from surrealdb import ExportOptions

buffer = io.BytesIO()
db.export_to(buffer, ExportOptions(records=False))

A file object opened in text mode raises TypeError, because the export arrives as bytes.

import_() imports SurrealQL into the selected database. Its name ends in an underscore because import is a keyword in Python. It takes the SurrealQL as a str or as bytes, or the path of a file that holds it, as a pathlib.Path or another path-like object:

import pathlib

db.import_(pathlib.Path("backup.surql"))

The SDK sends a file as it reads it, so a large file is not held in memory.

A str is always the SurrealQL itself, so import_("backup.surql") would send the name of the file as SurrealQL. To prevent that mistake, a str that names an existing file raises ValueError. Pass the path as pathlib.Path("backup.surql") to import the file.

SurrealDB 3.0 and later require an import to start with the statement OPTION IMPORT;. Every export starts with it, so the output of export() and export_to() can be imported as it is. For SurrealQL that you write yourself, put the statement first:

db.import_(
    "OPTION IMPORT;\n"
    "CREATE person:lena CONTENT { name: 'Lena' };\n"
)

Without it, SurrealDB 3.0 and later refuse the import with HttpStatusError and status 400. SurrealDB 2.x accepts an import without it.

OPTION IMPORT; turns off events, live queries and the processing of fields for the rest of the import, so a statement writes its values as they are, without the type checks, assertions and defaults of DEFINE FIELD. To run statements with their usual effects, send them with query() instead.

A statement that fails does not stop the import: the server runs every statement, and applies the ones that succeed. If any statement failed, import_() raises ImportFailedError at the end. Its failures attribute holds a ServerError for each statement that failed.

The example below imports the backup from Writing an export to a file into the database that it came from, where the records already exist:

import pathlib

from surrealdb import ImportFailedError, Surreal

with Surreal("ws://localhost:8000") as db:
    db.signin({"username": "root", "password": "secret"})
    db.use("surrealdb", "docs")

    try:
        db.import_(pathlib.Path("backup.surql"))
    except ImportFailedError as error:
        for failure in error.failures:
            print(type(failure).__name__, failure)
Output
AlreadyExistsError Database record `person:jaime` already exists

Against SurrealDB 2.x, every failure is an InternalError, because the kinds of error need SurrealDB 3.0 or later.

An export does not hold the key of an access method. It writes a placeholder in place of the key, and the server refuses the placeholder on import. An import therefore reports one failure for each access method that has a key, including every record access method. Define those access methods again after the import.

export(), export_to() and import_() are not limited by the timeout option of the connection, because a transfer can take much longer than a single request. To set a limit, call them inside a timeout() block:

with db.timeout(600):
    db.export_to("backup.surql")

When the limit passes, the call raises TransportTimeoutError.

Was this page helpful?