DB.Export writes the namespace and database of the default session as a SurrealQL document. DB.Import runs such a document. Use the two methods together to back up and restore a database, or to copy a database to another server. This page covers how to export a database, and how to choose what to export. It also covers how to import a document, and what to do when some of its statements fail.
API references
Method | Description |
|---|---|
db.Export(ctx, w, options) | Writes the database as SurrealQL to an io.Writer |
db.Import(ctx, document) | Runs a SurrealQL document from an io.Reader |
ExportOptions | Chooses what an export holds |
ImportError | Lists the statements of an import that failed |
How import and export work
Both methods send an HTTP request to the server, whichever transport the client uses: Export sends POST /export, and Import sends POST /import. They work on WebSocket and HTTP connections alike, in the namespace and database of the default session.
Both methods authenticate with the token that the client last received, and do not use the WebSocket session. That token comes from .SignIn(), .SignUp(), .Authenticate() or a renewal. A WebSocket session can outlive its token. By default, the token of a system user lasts one hour. After the token expires, Export and Import fail with 401 Unauthorized, but queries still work. Sign in again to get a new token. A client that has not signed in gets 403 Forbidden.
Exporting a database
Export writes the document to any io.Writer, such as a file, a buffer or an HTTP response. With a nil options value, Export exports every definition and every record:
f, err := os.Create("backup.surql")
if err != nil {
log.Fatal(err)
}
defer f.Close()
if err := db.Export(ctx, f, nil); err != nil {
log.Fatal(err)
}The document starts with OPTION IMPORT;. After that statement, it holds the definitions and the records of each table. For a database with one person record, the document looks like this:
-- ------------------------------
-- OPTION
-- ------------------------------
OPTION IMPORT;
-- ------------------------------
-- TABLE: person
-- ------------------------------
DEFINE TABLE person TYPE NORMAL SCHEMAFULL PERMISSIONS NONE;
DEFINE FIELD OVERWRITE name ON person TYPE string PERMISSIONS FULL;
-- ------------------------------
-- TABLE DATA: person
-- ------------------------------
INSERT [ { id: person:tobie, name: 'Tobie' } ];Export writes the document as the server produces it, and does not close the writer.
Choosing what to export
Pass ExportOptions to leave parts out. The zero value of ExportOptions exports what the server exports by default:
err := db.Export(ctx, f, &surrealdb.ExportOptions{
Tables: []string{"person", "post"},
ExcludeUsers: true,
ExcludeRecords: false,
})| Field | What it does |
|---|---|
Tables | Limits the export to these tables, when it is not empty |
ExcludeRecords | Exports the definitions of tables, without their records |
ExcludeUsers | Leaves out DEFINE USER statements |
ExcludeAccesses | Leaves out DEFINE ACCESS statements |
ExcludeParams | Leaves out DEFINE PARAM statements |
ExcludeFunctions | Leaves out DEFINE FUNCTION statements |
ExcludeAnalyzers | Leaves out DEFINE ANALYZER statements |
An export over HTTP cannot hold the history of a versioned table, because the server refuses that option over HTTP.
Importing SurrealQL
Import runs a SurrealQL document from any io.Reader, in the namespace and database of the default session:
f, err := os.Open("backup.surql")
if err != nil {
log.Fatal(err)
}
defer f.Close()
if err := db.Use(ctx, "surrealdb", "restored"); err != nil {
log.Fatal(err)
}
if err := db.Import(ctx, f); err != nil {
log.Fatal(err)
}Import does not close the reader, so close it yourself.
The OPTION IMPORT statement
The server requires an imported document to start with OPTION IMPORT;. An exported document already starts with that statement. Without it, Import fails with 400 Bad Request and the message Import requires `OPTION IMPORT;` as the first statement. To import a document of your own, add the statement at the start:
document := strings.NewReader(`OPTION IMPORT;
CREATE person:jaime SET name = 'Jaime';
CREATE person:ana SET name = 'Ana';`)
err := db.Import(ctx, document)OPTION IMPORT turns off events, live queries, field processing and the output of each statement, so that the import runs fast. The server does not check field types and assertions. It stores a value unchanged, even when a DEFINE FIELD statement would refuse that value. To run statements with every side effect, use Query instead.
Handling statements that fail
The server keeps the changes of the statements that succeed, even when other statements in the document fail. When statements fail, Import returns an *ImportError that lists their errors in order:
err := db.Import(ctx, document)
var ie *surrealdb.ImportError
if errors.As(err, &ie) {
for _, failure := range ie.Failures {
var se *surrealdb.ServerError
if errors.As(failure, &se) {
log.Printf("%s: %s", se.Kind, se.Message)
}
}
}AlreadyExists: Database record `person:tobie` already existsEach failure unwraps to a *ServerError, so the Is helpers work on it. The server does not roll back the statements that succeeded. To import all or nothing, import into an empty database. If the import fails, remove that database.
Learn more
DB API reference for the signatures of
ExportandImportError handling for
ImportErrorsurreal db export and surreal db import for the same operations from the command line