Multiple sessions

Sessions allow you to create isolated contexts on a single WebSocket connection. Each session has its own authentication state, namespace and database selection, and connection variables. This is useful when a single application needs to serve multiple users or tenants over one connection.

Sessions require a WebSocket connection (ws:// or wss://) and SurrealDB v3 or later.

API References

MethodDescription
db.Attach(ctx)Creates a new session on the connection
session.Detach(ctx)Removes the session from the server
session.ID()Returns the session's UUID

Creating a session

Call .Attach() on the *DB to create a new session. The session starts unauthenticated and without a selected namespace or database, so you must configure it before making queries.

session, err := db.Attach(ctx)
if err != nil {
log.Fatal(err)
}
defer session.Detach(ctx)

_, err = session.SignIn(ctx, surrealdb.Auth{
Username: "root",
Password: "root",
})
if err != nil {
log.Fatal(err)
}

if err := session.Use(ctx, "my_ns", "my_db"); err != nil {
log.Fatal(err)
}

Querying with a session

Sessions satisfy the sendable constraint, so all generic functions like Query, Select, Create, etc. accept a *Session directly.

results, err := surrealdb.Query[[]Person](ctx, session,
"SELECT * FROM persons",
nil,
)

Each session maintains its own state. Changes to variables, authentication, or namespace on one session do not affect the parent *DB or other sessions.

Session isolation

Sessions are fully isolated from each other and from the parent connection:

  • Authentication is independent: signing in on a session does not affect other sessions or the *DB.

  • .Use() on a session does not change the namespace/database of other sessions.

  • Variables set with .Let() are scoped to the session.

  • Live queries started on a session are scoped to that session.

sessionA, _ := db.Attach(ctx)
defer sessionA.Detach(ctx)

sessionB, _ := db.Attach(ctx)
defer sessionB.Detach(ctx)

sessionA.SignIn(ctx, surrealdb.Auth{Username: "admin", Password: "admin"})
sessionA.Use(ctx, "ns_a", "db_a")

sessionB.SignIn(ctx, surrealdb.Auth{Namespace: "ns_b", Database: "db_b", Access: "user_access", Username: "user1", Password: "pass1"})
sessionB.Use(ctx, "ns_b", "db_b")

Starting transactions from a session

Sessions can start their own transactions using .Begin(). The transaction inherits the session's authentication and namespace context.

tx, err := session.Begin(ctx)
if err != nil {
log.Fatal(err)
}
defer tx.Cancel(ctx)

surrealdb.Create[any](ctx, tx, models.Table("events"), map[string]any{"type": "login"})

if err := tx.Commit(ctx); err != nil {
log.Fatal(err)
}

See Transactions for more on interactive transactions.

Detaching a session

Call .Detach() to remove the session from the server. After detaching, the session cannot be used and any operations on it return ErrSessionClosed.

if err := session.Detach(ctx); err != nil {
log.Fatal(err)
}

Use defer session.Detach(ctx) immediately after .Attach() to ensure cleanup.

Learn more