Data manipulation
The Go SDK provides generic top-level functions for common CRUD operations on records and tables. These functions work with *DB, *Session, and *Transaction through the sendable constraint, and return typed results through Go generics.
This page covers how to target tables and records, and how to select, create, insert, update, merge, patch, and delete data.
API References
| Function | Description |
|---|
surrealdb.Select[T](ctx, s, what) | Selects all records from a table, or a specific record |
surrealdb.Create[T](ctx, s, what, data) | Creates a new record with optional data |
surrealdb.Insert[T](ctx, s, table, data) | Inserts one or multiple records into a table |
surrealdb.InsertRelation[T](ctx, s, rel) | Inserts a relation record between two records |
surrealdb.Relate[T](ctx, s, rel) | Creates a relation with an auto-generated ID |
surrealdb.Update[T](ctx, s, what, data) | Replaces the entire content of a record or all records in a table |
surrealdb.Upsert[T](ctx, s, what, data) | Creates a record if it does not exist, or replaces it entirely |
surrealdb.Merge[T](ctx, s, what, data) | Merges data into a record, preserving unmentioned fields |
surrealdb.Patch(ctx, s, what, patches) | Applies JSON Patch operations to a record or table |
surrealdb.Delete[T](ctx, s, what) | Deletes a specific record or all records from a table |
Targeting tables and records
Most data manipulation functions accept a what parameter that determines the scope of the operation. You can pass a Table to target all records in a table, or a RecordID to target a specific record.
import "github.com/surrealdb/surrealdb.go/pkg/models"
all, err := surrealdb.Select[[]Person](ctx, db, models.Table("persons"))
one, err := surrealdb.Select[Person](ctx, db, models.NewRecordID("persons", "tobie"))
When a Table is passed, operations that return data return a slice. When a RecordID is passed, they return a single value. Use the appropriate type parameter to match.
Selecting records
Select retrieves records from the database. Pass a Table to get all records, or a RecordID to get a single record.
persons, err := surrealdb.Select[[]Person](ctx, db, models.Table("persons"))
if err != nil {
log.Fatal(err)
}
tobie, err := surrealdb.Select[Person](ctx, db, models.NewRecordID("persons", "tobie"))
if err != nil {
log.Fatal(err)
}
Creating records
Create creates a new record. Pass a Table to generate a random ID, or a RecordID to specify the ID explicitly. The data can be a struct or a map.
person, err := surrealdb.Create[Person](ctx, db, models.Table("persons"), Person{
Name: "Tobie",
Surname: "Morgan Hitchcock",
})
specific, err := surrealdb.Create[Person](ctx, db, models.NewRecordID("persons", "tobie"), map[string]any{
"name": "Tobie",
"surname": "Morgan Hitchcock",
})
Inserting records
Insert inserts one or more records into a table. This is useful for bulk operations.
persons, err := surrealdb.Insert[Person](ctx, db, models.Table("persons"), []map[string]any{
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
})
Creating relations
The SDK provides two ways to create graph edges between records.
Relate creates a relation with an auto-generated ID. The Relationship.ID field is ignored.
rel, err := surrealdb.Relate[map[string]any](ctx, db, &surrealdb.Relationship{
In: models.NewRecordID("persons", "tobie"),
Out: models.NewRecordID("posts", "first"),
Relation: models.Table("wrote"),
Data: map[string]any{"created_at": "2026-01-01T00:00:00Z"},
})
InsertRelation works like Insert but for relation tables. It allows you to specify the ID explicitly via the Relationship.ID field.
rel, err := surrealdb.InsertRelation[map[string]any](ctx, db, &surrealdb.Relationship{
In: models.NewRecordID("persons", "tobie"),
Out: models.NewRecordID("posts", "first"),
Relation: models.Table("wrote"),
})
Replacing records
Update replaces the entire content of a record or all records in a table. Fields not included in the new data are removed.
updated, err := surrealdb.Update[Person](ctx, db, models.NewRecordID("persons", "tobie"), Person{
Name: "Tobie",
Surname: "Morgan Hitchcock",
})
Because Update performs a full replacement, omitted fields are deleted from the record. Use Merge if you want to preserve existing fields.
Upserting records
Upsert creates a record if it does not already exist, or replaces it entirely if it does.
person, err := surrealdb.Upsert[Person](ctx, db, models.NewRecordID("persons", "tobie"), Person{
Name: "Tobie",
Surname: "Morgan Hitchcock",
})
Merging data
Merge deep-merges the provided data into the existing record, preserving fields not mentioned in the merge payload.
merged, err := surrealdb.Merge[Person](ctx, db, models.NewRecordID("persons", "tobie"), map[string]any{
"age": 35,
})
Applying patches
Patch applies JSON Patch (RFC 6902) operations to a record or all records in a table. Each operation is a PatchData with Op, Path, and Value fields.
patches, err := surrealdb.Patch(ctx, db, models.NewRecordID("persons", "tobie"), []surrealdb.PatchData{
{Op: "replace", Path: "/surname", Value: "Hitchcock"},
{Op: "add", Path: "/verified", Value: true},
})
Supported operations include add, remove, replace, move, copy, and test.
Deleting records
Delete removes a specific record or all records from a table. The function returns the deleted record(s).
deleted, err := surrealdb.Delete[Person](ctx, db, models.NewRecordID("persons", "tobie"))
allDeleted, err := surrealdb.Delete[[]Person](ctx, db, models.Table("persons"))
Learn more