Skip to content

Go

Migrating to Go SDK 2.x

Version 2 of the Go SDK supports SurrealDB 4.0. It changes the module path, the supported server versions, and how the SDK sends some Go values to the server. This guide lists each change that can break a project written for version 1, with the 1.x code and the 2.x code that replaces it. The sections are in order of how much code each change usually affects, so work through them from the top.

Important

Version 1 cannot write a time.Time to SurrealDB 4.0. It sends a bare time.Time as text, which SurrealDB 4.0 refuses with CBOR tag 0 (a datetime as text) is not accepted: send tag 12 [seconds, nanos]. Version 2 works with SurrealDB 3.3.0 and later. If the server is older than 3.3, upgrade it to 3.3 or later first. Then move to version 2 while the server runs 3.3 or a later 3.x release. After that, upgrade the server to 4.0.

  • The module path is github.com/surrealdb/surrealdb.go/v2, so every import changes.

  • The SDK supports SurrealDB 3.3.0 and later, before 5.0.0. Version 1 supported 2.1.0 and later.

  • The SDK sends a zero time.Time as NONE and a time.Duration as a duration, and refuses a regexp.Regexp.

  • On SurrealDB 4.0 the SDK uses cbor.2. Sized numbers keep their kind when the SDK sends them and when it receives them, and decoding into any gives the exact Go type.

  • The CRUD functions run SurrealQL through the query RPC method, so the text of some errors is different.

  • surrealql.SinceVersionstamp sends the versionstamp unchanged.

Add the new module:

go get github.com/surrealdb/surrealdb.go/v2

Then change every import of the SDK, including pkg/..., contrib/... and memory, to the /v2 path:

1.x
import (
	surrealdb "github.com/surrealdb/surrealdb.go"
	"github.com/surrealdb/surrealdb.go/pkg/models"
)
2.x
import (
	surrealdb "github.com/surrealdb/surrealdb.go/v2"
	"github.com/surrealdb/surrealdb.go/v2/pkg/models"
)

The package names do not change, so the code that uses them stays as it is. To rewrite the imports in every Go file of a module at once, run this command from the module root:

perl -pi -e 's#"github\.com/surrealdb/surrealdb\.go(?!/v2)#"github.com/surrealdb/surrealdb.go/v2#g' $(grep -rl --include='*.go' 'github.com/surrealdb/surrealdb.go' .)

Then remove the version 1 requirement from go.mod:

go mod tidy

Version 2 needs Go 1.24 or later, as the later 1.x releases do.

Version 2 supports SurrealDB 3.3.0 and later versions before 5.0.0, pre-releases included. SurrealDB 4.0 is the recommended version. With a 3.x server, the kinds that 4.0 adds are not available, and error kinds are less precise.

The SDK does not check the version unless you ask it to. With WithVersionCheck(true), connecting to a 2.x, 3.0, 3.1 or 3.2 server now fails with an UnsupportedVersionError:

db, err := surrealdb.FromEndpointURLStringWithOptions(ctx, "ws://localhost:8000",
	surrealdb.WithVersionCheck(true),
)
Error output with SurrealDB 3.2
SurrealDB server version "3.2.4+20260803.93ab219" is not supported by this SDK (supported: >= 3.3.0, < 5.0.0); to connect anyway, turn the check off with surrealdb.WithVersionCheck(false)

surrealdb.MinimumServerVersion is now "3.3.0", and IsVersionSupported returns false for versions before it. Code that compares a version with MinimumServerVersion itself, for example in a health check, now refuses servers that version 1 accepted.

Version 2 sends some standard library values as different SurrealDB kinds:

Go value1.x sent2.x sends
A zero time.TimeNULLNONE
A time.Time that is not zeroIts text, which SurrealDB 4.0 refusesA datetime, with its nanoseconds
time.DurationAn int of nanosecondsA duration
regexp.Regexp, *regexp.RegexpAn empty object {}An encoding error. Use models.Regex.
A uint64 above math.MaxInt64An integer that SurrealDB refusesA decimal, or a u64 on SurrealDB 4.0
A models.CustomDurationString that is not a valid durationA stringAn encoding error

The SDK converts these values wherever they are: in a struct field, a map, a slice, or a variable of Query.

Then check the schema for the fields that your code writes these values to:

  • A field of TYPE datetime | null refuses a zero time.Time, because the SDK now sends that value as NONE. The error is Expected `datetime | null` but found `NONE` . Define the field as option<datetime>, or send a nil *time.Time to store NULL.

  • A field of TYPE int that stores a time.Duration refuses the new values, with Expected `int` but found `1m` . A query that compares such a field with an integer also stops matching. Give the field a type that accepts a duration, such as int | duration. Integers that are already stored still decode into a time.Duration.

  • Use a models.Regex for a regular expression. A models.Regex holds the pattern as text. SurrealDB compiles the pattern with the syntax of the Rust regex crate, which is close to Go's but not the same.

1.x
pattern := regexp.MustCompile(`^[a-z]+$`)
db.Let(ctx, "pattern", pattern)
2.x
pattern := models.Regex{Pattern: `^[a-z]+$`}
db.Let(ctx, "pattern", pattern)

A models.Regex needs SurrealDB 4.0. Over plain CBOR, which earlier servers use, it fails to encode. See Value types for every kind.

On WebSocket and HTTP, the SDK now offers cbor.2, the CBOR dialect of SurrealDB 4.0. The SDK uses cbor.2 when the server accepts it. Over cbor.2:

  • The SDK sends int8, uint8, int16, uint16, int32, uint32 and float32 values as the sized numbers i8 to u32 and f32, and models.Float16 as f16.

  • A sized number decodes into any as the exact Go type, such as int8 or float32. Version 1 gave a widened uint64, int64 or float64. The new kinds of SurrealDB 4.0 decode into any as their models types, such as models.PlainDate and models.Regex.

Code that decodes into any or map[string]any and then asserts the type can stop matching. In this example, the program wrote the level field from a Go int32. Version 1 stored the value as an int, which read back as a uint64. Version 2 stores it as an i32, which reads back as an int32:

1.x
level := row["level"].(uint64)
2.x
level := row["level"].(int32)

If you decode into a struct field of a concrete type, such as Level int, the SDK converts every numeric kind. This works the same in both versions. It is the simpler fix when you know the shape of the data.

To keep plain CBOR, set DisableCBORv2 in the connection configuration. db.CBORVersion() reports which version a connection uses. A connection that uses the deprecated models.CborMarshaler and models.CborUnmarshaler stays on plain CBOR.

Select, Create, Update, Upsert, Merge, Patch, Delete, Insert, InsertRelation, Relate, Live and Kill now send a SurrealQL statement with the query RPC method. In version 1, each of these functions called its own RPC method, such as select or insert_relation. Results have the same shape, and a failure is still an *RPCError that unwraps to a *ServerError.

Two things can be different:

  • The text of an error message. Match on the error kind rather than on the message. Use errors.As or an Is* helper, such as surrealdb.IsNotFound.

  • Server settings that limit the query method now apply to these functions too.

In the query builder, ShowChangesForTableQuery.SinceVersionstamp now sends the versionstamp as it is. Version 1 shifted it right by 16 bits first. Pass a versionstamp exactly as SHOW CHANGES returned it:

2.x
q := surrealql.ShowChangesForTable("reading").SinceVersionstamp(versionstamp).Limit(10)

SINCE is inclusive. When you continue from the last change that you received, the server returns that change again.

Releases 1.6 to 1.8 added features that change how a client behaves by default. A project that moves to version 2 from an earlier 1.x release gets them too:

  • A WebSocket client reconnects by itself. When the connection drops, the client connects again and restores the namespace, database, variables, authentication, sessions and live queries. A request that you send during the reconnect waits until the reconnect finishes or its context ends. It does not fail at once. Pass WithReconnect(false) for the earlier behaviour. See Reliable connections.

  • Package spectron is now memory. Import the Agent Memory client from github.com/surrealdb/surrealdb.go/v2/memory.

  • A live query channel closes when the server kills the query. A notification with the action KILLED ends it.

  • New methods and types for Health, Refresh, Revoke, Reset, token renewal, selecting a range of records, the error kind helpers, and the Set and File values.

1.x import2.x import
github.com/surrealdb/surrealdb.gogithub.com/surrealdb/surrealdb.go/v2
github.com/surrealdb/surrealdb.go/pkg/modelsgithub.com/surrealdb/surrealdb.go/v2/pkg/models
github.com/surrealdb/surrealdb.go/pkg/connectiongithub.com/surrealdb/surrealdb.go/v2/pkg/connection
github.com/surrealdb/surrealdb.go/pkg/constantsgithub.com/surrealdb/surrealdb.go/v2/pkg/constants
github.com/surrealdb/surrealdb.go/surrealcborgithub.com/surrealdb/surrealdb.go/v2/surrealcbor
github.com/surrealdb/surrealdb.go/contrib/rewsgithub.com/surrealdb/surrealdb.go/v2/contrib/rews
github.com/surrealdb/surrealdb.go/contrib/surrealqlgithub.com/surrealdb/surrealdb.go/v2/contrib/surrealql
github.com/surrealdb/surrealdb.go/memorygithub.com/surrealdb/surrealdb.go/v2/memory
  1. Run go get github.com/surrealdb/surrealdb.go/v2. Rewrite the imports. Then run go mod tidy.

  2. Check that the server runs SurrealDB 3.3.0 or later. Upgrade the server to 4.0 after you upgrade the SDK.

  3. Find the fields that store a zero time.Time or a time.Duration. Update their types in the schema.

  4. Replace every regexp.Regexp that your code sends to the server with a models.Regex.

  5. Find type assertions on values that your code decodes into any. Change them to allow for the sized Go types.

  6. Replace checks on error message text with checks on the error kind.

  7. Pass versionstamps to SinceVersionstamp as SHOW CHANGES returns them.

  8. Run your tests against SurrealDB 4.0.

Was this page helpful?