The Surreal and AsyncSurreal factory functions create a connection to a SurrealDB instance. They inspect the URL scheme and return the appropriate connection class (WebSocket, HTTP, or embedded), so you use the same interface regardless of protocol.
Surreal(url) returns a blocking (synchronous) connection. AsyncSurreal(url) returns an asynchronous connection. Both expose the same set of methods; the async variants must be awaited.
Source: surrealdb.py
Factory functions
Surreal(url)
Creates a synchronous connection based on the URL scheme.
from surrealdb import Surreal
db = Surreal(url)Parameter | Type | Description |
|---|---|---|
url | str | The connection URL. The scheme determines the connection type. |
Returns: BlockingWsSurrealConnection | BlockingHttpSurrealConnection | BlockingEmbeddedSurrealConnection
AsyncSurreal(url)
Creates an asynchronous connection based on the URL scheme.
from surrealdb import AsyncSurreal
db = AsyncSurreal(url)Parameter | Type | Description |
|---|---|---|
url | str | The connection URL. The scheme determines the connection type. |
Returns: AsyncWsSurrealConnection | AsyncHttpSurrealConnection | AsyncEmbeddedSurrealConnection
URL schemes
| Scheme | Connection Type | Description |
|---|---|---|
ws://, wss:// | WebSocket | Full-featured stateful connection. Supports live queries, sessions, and transactions. |
http://, https:// | HTTP | Stateless connection. Each request is independent. |
mem://, memory:// | Embedded (in-memory) | In-process database that does not persist data. |
file://, surrealkv:// | Embedded (on-disk) | In-process database backed by SurrealKV storage. |
Examples
from surrealdb import Surreal
db = Surreal("ws://localhost:8000")from surrealdb import Surreal
db = Surreal("https://cloud.surrealdb.com")from surrealdb import Surreal
db = Surreal("mem://")from surrealdb import Surreal
db = Surreal("surrealkv://path/to/database")from surrealdb import AsyncSurreal
db = AsyncSurreal("ws://localhost:8000")Connection methods
.connect()
Opens the connection to the SurrealDB instance. The URL can optionally be overridden here.
db.connect(url)Parameter | Type | Description |
|---|---|---|
url | str | None | An optional URL to override the one provided to the factory function. Defaults to None. |
Returns: None
Examples
from surrealdb import Surreal
db = Surreal("ws://localhost:8000")
db.connect()from surrealdb import AsyncSurreal
db = AsyncSurreal("ws://localhost:8000")
await db.connect()db = Surreal("ws://localhost:8000")
db.connect("ws://other-host:8000") .close()
Closes the active connection and releases resources.
db.close()Returns: None
Examples
db.close()await db.close() .use()
Switches to a specific namespace and database.
db.use(namespace, database)Parameter | Type | Description |
|---|---|---|
namespace | str | The namespace to use. |
database | str | The database to use. |
Returns: None
Examples
db.use("my_namespace", "my_database")await db.use("my_namespace", "my_database") .version()
Returns the version string of the connected SurrealDB instance.
db.version()Returns: str
Examples
ver = db.version()
print(ver) # e.g. "surrealdb-2.2.0"ver = await db.version()
print(ver)Authentication methods
.signup()
Signs up a user to a specific access method.
db.signup(vars)Parameter | Type | Description |
|---|---|---|
vars | dict[str, Value ] | Variables used for signup, including namespace, database, access, and any additional fields required by the access method. |
Returns: Tokens
Examples
token = db.signup({
"namespace": "my_namespace",
"database": "my_database",
"access": "user_access",
"email": "user@example.com",
"password": "s3cret",
})token = await db.signup({
"namespace": "my_namespace",
"database": "my_database",
"access": "user_access",
"email": "user@example.com",
"password": "s3cret",
}) .signin()
Signs in to the database with the given credentials.
db.signin(vars)Parameter | Type | Description |
|---|---|---|
vars | dict[str, Value ] | Credentials for authentication. For root access, provide usernameand password. For scoped access, also include namespace, database, and access. |
Returns: Tokens
Examples
token = db.signin({
"username": "root",
"password": "root",
})token = await db.signin({
"username": "root",
"password": "root",
})token = db.signin({
"namespace": "my_namespace",
"database": "my_database",
"access": "user_access",
"email": "user@example.com",
"password": "s3cret",
}) .authenticate()
Authenticates the current connection with a JWT token.
db.authenticate(token)Parameter | Type | Description |
|---|---|---|
token | str | The JWT token to authenticate with. |
Returns: None
Examples
db.authenticate("eyJhbGciOiJIUzI1NiIs...")await db.authenticate("eyJhbGciOiJIUzI1NiIs...") .invalidate()
Invalidates the authentication for the current connection, removing the associated JWT token.
db.invalidate()Returns: None
Examples
db.invalidate()await db.invalidate() .info()
Returns the record of the currently authenticated user.
db.info()Returns: Value
Examples
user = db.info()
print(user) # e.g. {"id": "users:john", "email": "john@example.com"}user = await db.info()Variables
.let()
Defines a variable on the current connection that can be used in subsequent queries.
db.let(key, value)Parameter | Type | Description |
|---|---|---|
key | str | The name of the variable (without the $prefix). |
value | Value | The value to assign to the variable. |
Returns: None
Examples
db.let("user_id", RecordID("users", "john"))
result = db.query("SELECT * FROM users WHERE id = $user_id")await db.let("user_id", RecordID("users", "john"))
result = await db.query("SELECT * FROM users WHERE id = $user_id") .unset()
Removes a previously defined variable from the current connection.
db.unset(key)Parameter | Type | Description |
|---|---|---|
key | str | The name of the variable to remove. |
Returns: None
Examples
db.unset("user_id")await db.unset("user_id")Query methods
.query()
Runs a set of SurrealQL statements against the database. Returns an awaitable (async) or lazy (sync) builder.
db.query(query, vars) Behaviour change in v3.0. .query() now surfaces every statement result. When the server returns a single statement result it returns the result directly; when it returns multiple results it returns a tuple[Value, ...]. This fixes the silent-discard behaviour reported in issue #232.
Parameter | Type | Description |
|---|---|---|
query | str | The SurrealQL query string to execute. |
vars | dict[str, Value ] | None | Variables to bind into the query. Defaults to None. |
Returns: Value for a single-statement query, otherwise tuple[Value, ...] of statement results.
The returned object also exposes .into(cls) which maps the N statement results positionally onto the fields of a dataclass (or any class accepting keyword arguments).
Examples
result = await db.query(
"SELECT * FROM users WHERE age > $min_age",
{"min_age": 18},
)people, count = await db.query(
"SELECT * FROM person; SELECT count() FROM person GROUP ALL"
)from dataclasses import dataclass
@dataclass
class Stats:
people: list
count: list
stats = await db.query(
"SELECT * FROM person; SELECT count() FROM person GROUP ALL"
).into(Stats)# The sync builder auto-executes when consumed (indexed, iterated, compared, etc.).
# For fire-and-forget statements call .execute() explicitly.
people = db.query("SELECT * FROM users")
print(len(people))
db.query("DELETE temp_data;").execute() .query_raw()
Runs a set of SurrealQL statements and returns the raw RPC response, including per-statement results, statuses, and execution times. Unlike .query(), errors in individual statements are returned in the response rather than raised as exceptions.
db.query_raw(query, params)Parameter | Type | Description |
|---|---|---|
query | str | The SurrealQL query string to execute. |
params | dict[str, Value ] | None | Variables to bind into the query. Defaults to None. |
Returns: dict[str, Any]
Examples
raw = db.query_raw(
"CREATE users SET name = $name; SELECT * FROM users;",
{"name": "John"},
)
for statement in raw["result"]:
print(statement["status"], statement["time"])raw = await db.query_raw(
"CREATE users SET name = $name; SELECT * FROM users;",
{"name": "John"},
)CRUD methods
v3.0 builder pattern. .create(), .update(), .upsert(), .delete(), and .insert() return an awaitable (async) or lazy (sync) builder. The builder exposes chainable clause methods that map directly to SurrealQL clauses:
Calling .create(record, data) is sugar for .create(record).content(data). The standalone .merge(), .patch(), and .insert_relation() methods from v2.x have been removed.
.select()
Selects all records in a table, or a specific record by its ID.
db.select(record)Parameter | Type | Description |
|---|---|---|
record | RecordIdType | A table name ( str) or a RecordIDto select. |
Returns: Value
Examples
users = db.select("users")
user = db.select(RecordID("users", "john"))users = await db.select("users")
user = await db.select(RecordID("users", "john")) .create()
Creates a record in a table. If a RecordID is passed, the record is created with that specific ID. If a table name is passed, a random ID is generated.
db.create(record, data)Parameter | Type | Description |
|---|---|---|
record | RecordIdType | The table name or RecordIDto create. |
data | Value | None | The record data. Defaults to None. |
Returns: Value
Examples
user = db.create("users", {
"name": "John",
"email": "john@example.com",
})
product = db.create(RecordID("products", "apple"), {
"name": "Apple",
"price": 1.50,
})user = await db.create("users", {
"name": "John",
"email": "john@example.com",
}) .update()
Replaces the entire record with the given data. Fields not present in data are removed.
db.update(record, data)Parameter | Type | Description |
|---|---|---|
record | RecordIdType | The table name or RecordIDto update. |
data | Value | None | The new record data. Defaults to None. |
Returns: Value
Examples
db.update(RecordID("users", "john"), {
"name": "John Doe",
"email": "john.doe@example.com",
})await db.update(RecordID("users", "john"), {
"name": "John Doe",
"email": "john.doe@example.com",
}) .upsert()
Updates an existing record or creates a new one if it does not exist. Replaces the entire record content.
db.upsert(record, data)Parameter | Type | Description |
|---|---|---|
record | RecordIdType | The table name or RecordIDto upsert. |
data | Value | None | The record data. Defaults to None. |
Returns: Value
Examples
db.upsert(RecordID("users", "john"), {
"name": "John",
"email": "john@example.com",
})await db.upsert(RecordID("users", "john"), {
"name": "John",
"email": "john@example.com",
}) .merge clause
.merge(data) is a builder clause method - chain it on .update(), .upsert(), or .create(). It compiles to ... MERGE $data and preserves any existing fields not present in data.
db.update(RecordID("users", "john")).merge({"age": 32})await db.update(RecordID("users", "john")).merge({"age": 32}) .patch clause
.patch(data) is a builder clause method - chain it on .update(), .upsert(), or .create(). It compiles to ... PATCH $data and applies JSON Patch operations.
db.update(RecordID("users", "john")).patch([
{"op": "replace", "path": "/email", "value": "new@example.com"},
{"op": "add", "path": "/verified", "value": True},
])await db.update(RecordID("users", "john")).patch([
{"op": "replace", "path": "/email", "value": "new@example.com"},
]) .delete()
Deletes all records in a table, or a specific record by its ID.
db.delete(record)Parameter | Type | Description |
|---|---|---|
record | RecordIdType | The table name or RecordIDto delete. |
Returns: Value
Examples
db.delete(RecordID("users", "john"))
db.delete("temp_data")await db.delete(RecordID("users", "john"))Insert methods
.insert()
Inserts one or more records into a table.
db.insert(table, data)Parameter | Type | Description |
|---|---|---|
table | str | Table | The table to insert into. |
data | Value | A single record dict or a list of record dicts to insert. |
Returns: Value
Examples
db.insert("users", {"name": "Alice", "email": "alice@example.com"})
db.insert("users", [
{"name": "Bob", "email": "bob@example.com"},
{"name": "Charlie", "email": "charlie@example.com"},
])await db.insert("users", {"name": "Alice", "email": "alice@example.com"})Inserting relations
The standalone .insert_relation() method from v2.x has been removed. Use .insert(table, data, relation=True) or chain .relation() on the insert builder to issue an INSERT RELATION INTO statement.
db.insert("likes", {
"in": RecordID("users", "alice"),
"out": RecordID("posts", "post1"),
}, relation=True)
# Or via the builder:
db.insert("likes").relation().content({
"in": RecordID("users", "alice"),
"out": RecordID("posts", "post1"),
})await db.insert("likes", {
"in": RecordID("users", "alice"),
"out": RecordID("posts", "post1"),
}, relation=True)Calling functions
.run()
Calls a SurrealDB function and returns its result. The function name typically uses the fn:: prefix for user-defined functions or namespace prefixes for built-ins.
db.run(name, args, version)Parameter | Type | Description |
|---|---|---|
name | str | The fully-qualified function name, e.g. "fn::increment". |
args | list[ Value ] | None | Positional arguments forwarded to the function. |
version | str | None | Optional function version selector. |
Returns: Value
Examples
result = db.run("fn::increment", [1])greeting = await db.run("fn::greet", ["world"])Live queries
Live queries require a WebSocket connection (ws:// or wss://). HTTP and embedded connections raise UnsupportedFeatureError.
.live()
Initiates a live query for a table. Returns a UUID that identifies the live query and can be passed to .subscribe_live() and .kill().
db.live(table, diff)Parameter | Type | Description |
|---|---|---|
table | str | Table | The table to watch for changes. |
diff | bool | If True, notifications include JSON Patch diffs instead of full records. Defaults to False. |
Returns: UUID
Examples
query_uuid = db.live("users")
query_uuid = db.live("users", diff=True)query_uuid = await db.live("users") .subscribe_live()
Returns a generator that yields live query notifications for the given query UUID. Each notification is a dict containing the action ("CREATE", "UPDATE", "DELETE"), the record data, and the record ID.
db.subscribe_live(query_uuid)Parameter | Type | Description |
|---|---|---|
query_uuid | str | UUID | The UUID of the live query returned by .live(). |
Returns (sync): Generator[dict[str, Value], None, None]
Returns (async): AsyncGenerator[dict[str, Value], None]
Examples
query_uuid = db.live("users")
for notification in db.subscribe_live(query_uuid):
print(notification["action"], notification["result"])query_uuid = await db.live("users")
async for notification in db.subscribe_live(query_uuid):
print(notification["action"], notification["result"]) .kill()
Terminates a running live query by its UUID.
db.kill(query_uuid)Parameter | Type | Description |
|---|---|---|
query_uuid | str | UUID | The UUID of the live query to kill. |
Returns: None
Examples
db.kill(query_uuid)await db.kill(query_uuid)Sessions
Sessions require a WebSocket connection (ws:// or wss://). HTTP and embedded connections raise UnsupportedFeatureError.
Sessions allow you to create isolated contexts on a single connection, each with its own namespace, database, variables, and authentication state.
.new_session()
Creates a new isolated session on the current connection.
db.new_session()Returns (sync): BlockingSurrealSession
Returns (async): AsyncSurrealSession
Examples
session = db.new_session()
session.use("other_ns", "other_db")
result = session.select("users")session = await db.new_session()
await session.use("other_ns", "other_db")
result = await session.select("users") .attach()
Attaches to the server-side session associated with this connection and returns its session ID.
db.attach()Returns: UUID
Examples
session_id = db.attach()session_id = await db.attach() .detach()
Detaches from a server-side session.
db.detach(session_id)Parameter | Type | Description |
|---|---|---|
session_id | UUID | The session ID to detach from. |
Returns: None
Examples
db.detach(session_id)await db.detach(session_id)Transactions
Transactions require a WebSocket connection (ws:// or wss://). HTTP and embedded connections raise UnsupportedFeatureError.
Transactions let you group multiple operations into an atomic unit. Changes are only applied when the transaction is committed, and can be rolled back with cancel.
.begin()
Begins a new transaction, optionally within a specific session.
db.begin(session_id)Parameter | Type | Description |
|---|---|---|
session_id | UUID | None | The session to start the transaction in. If None, uses the default session. Defaults to None. |
Returns: UUID — the transaction ID
Examples
txn_id = db.begin()txn_id = await db.begin()session_id = db.attach()
txn_id = db.begin(session_id) .commit()
Commits a transaction, applying all changes made within it.
db.commit(txn_id, session_id)Parameter | Type | Description |
|---|---|---|
txn_id | UUID | The transaction ID returned by .begin(). |
session_id | UUID | None | The session the transaction belongs to. Defaults to None. |
Returns: None
Examples
txn_id = db.begin()
db.query("CREATE users SET name = 'Alice'")
db.commit(txn_id)txn_id = await db.begin()
await db.query("CREATE users SET name = 'Alice'")
await db.commit(txn_id) .cancel()
Cancels a transaction, discarding all changes made within it.
db.cancel(txn_id, session_id)Parameter | Type | Description |
|---|---|---|
txn_id | UUID | The transaction ID returned by .begin(). |
session_id | UUID | None | The session the transaction belongs to. Defaults to None. |
Returns: None
Examples
txn_id = db.begin()
db.query("DELETE users")
db.cancel(txn_id)txn_id = await db.begin()
await db.query("DELETE users")
await db.cancel(txn_id)Context manager
Both Surreal and AsyncSurreal support the context manager protocol. The connection is automatically opened on entry and closed on exit.
Synchronous
from surrealdb import Surreal
with Surreal("ws://localhost:8000") as db:
db.use("my_namespace", "my_database")
db.signin({"username": "root", "password": "root"})
users = db.select("users")Asynchronous
from surrealdb import AsyncSurreal
async with AsyncSurreal("ws://localhost:8000") as db:
await db.use("my_namespace", "my_database")
await db.signin({"username": "root", "password": "root"})
users = await db.select("users")Complete example
from surrealdb import Surreal, RecordID
with Surreal("ws://localhost:8000") as db:
db.use("shop", "inventory")
db.signin({"username": "root", "password": "root"})
db.create("products", {"name": "Laptop", "price": 999.99})
db.create("products", {"name": "Mouse", "price": 29.99})
products = db.select("products")
print("All products:", products)
cheap = db.query(
"SELECT * FROM products WHERE price < $max",
{"max": 100},
)
print("Affordable:", cheap)
db.update(RecordID("products", products[0]["id"].id)).merge({"stock": 50})
db.delete(RecordID("products", products[1]["id"].id))import asyncio
from surrealdb import AsyncSurreal, RecordID
async def main():
async with AsyncSurreal("ws://localhost:8000") as db:
await db.use("shop", "inventory")
await db.signin({"username": "root", "password": "root"})
await db.create("products", {"name": "Laptop", "price": 999.99})
products = await db.select("products")
print("Products:", products)
asyncio.run(main())See also
SurrealSession — Session management reference
SurrealTransaction — Transaction reference
Data types — Type aliases and value types
Errors — Error classes reference
Connecting to SurrealDB — Connection protocols and patterns