# Surreal

The Surreal and AsyncSurreal factory functions are the main entry points for connecting to and interacting with a SurrealDB instance from Python.

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](https://github.com/surrealdb/surrealdb.py)

## Factory functions {#factory-functions}

### `Surreal(url)` {#surreal-sync}

Creates a synchronous connection based on the URL scheme.

```python title="Syntax"
from surrealdb import Surreal

db = Surreal(url)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>url</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The connection URL. The scheme determines the connection type.</td>
        </tr>
    </tbody>
</table>

**Returns:** `BlockingWsSurrealConnection | BlockingHttpSurrealConnection | BlockingEmbeddedSurrealConnection`

### `AsyncSurreal(url)` {#surreal-async}

Creates an asynchronous connection based on the URL scheme.

```python title="Syntax"
from surrealdb import AsyncSurreal

db = AsyncSurreal(url)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>url</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The connection URL. The scheme determines the connection type.</td>
        </tr>
    </tbody>
</table>

**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

```python title="WebSocket"
from surrealdb import Surreal

db = Surreal("ws://localhost:8000")
```

```python title="HTTP"
from surrealdb import Surreal

db = Surreal("https://cloud.surrealdb.com")
```

```python title="Embedded in-memory"
from surrealdb import Surreal

db = Surreal("mem://")
```

```python title="Embedded on-disk"
from surrealdb import Surreal

db = Surreal("surrealkv://path/to/database")
```

```python title="Async WebSocket"
from surrealdb import AsyncSurreal

db = AsyncSurreal("ws://localhost:8000")
```

---

## Connection methods

### `.connect()` {#connect}

Opens the connection to the SurrealDB instance. The URL can optionally be overridden here.

```python title="Method Syntax"
db.connect(url)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>url</code> _(optional)_</td>
            <td><code>str | None</code></td>
            <td>An optional URL to override the one provided to the factory function. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
from surrealdb import Surreal

db = Surreal("ws://localhost:8000")
db.connect()
```

```python title="Asynchronous"
from surrealdb import AsyncSurreal

db = AsyncSurreal("ws://localhost:8000")
await db.connect()
```

```python title="Override URL"
db = Surreal("ws://localhost:8000")
db.connect("ws://other-host:8000")
```

### `.close()` {#close}

Closes the active connection and releases resources.

```python title="Method Syntax"
db.close()
```

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.close()
```

```python title="Asynchronous"
await db.close()
```

### `.use()` {#use}

Switches to a specific namespace and database.

```python title="Method Syntax"
db.use(namespace, database)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>namespace</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The namespace to use.</td>
        </tr>
        <tr>
            <td><code>database</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The database to use.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.use("my_namespace", "my_database")
```

```python title="Asynchronous"
await db.use("my_namespace", "my_database")
```

### `.version()` {#version}

Returns the version string of the connected SurrealDB instance.

```python title="Method Syntax"
db.version()
```

**Returns:** `str`

#### Examples

```python title="Synchronous"
ver = db.version()
print(ver)  # e.g. "surrealdb-2.2.0"
```

```python title="Asynchronous"
ver = await db.version()
print(ver)
```

---

## Authentication methods

### `.signup()` {#signup}

Signs up a user to a specific access method.

```python title="Method Syntax"
db.signup(vars)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>vars</code> _(required)_</td>
            <td><code>dict[str, <a href="/docs/reference/python/api/types/#value">Value</a>]</code></td>
            <td>Variables used for signup, including <code>namespace</code>, <code>database</code>, <code>access</code>, and any additional fields required by the access method.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Tokens`](/docs/reference/python/api/types/#tokens)

#### Examples

```python title="Synchronous"
token = db.signup({
    "namespace": "my_namespace",
    "database": "my_database",
    "access": "user_access",
    "email": "user@example.com",
    "password": "s3cret",
})
```

```python title="Asynchronous"
token = await db.signup({
    "namespace": "my_namespace",
    "database": "my_database",
    "access": "user_access",
    "email": "user@example.com",
    "password": "s3cret",
})
```

### `.signin()` {#signin}

Signs in to the database with the given credentials.

```python title="Method Syntax"
db.signin(vars)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>vars</code> _(required)_</td>
            <td><code>dict[str, <a href="/docs/reference/python/api/types/#value">Value</a>]</code></td>
            <td>Credentials for authentication. For root access, provide <code>username</code> and <code>password</code>. For scoped access, also include <code>namespace</code>, <code>database</code>, and <code>access</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Tokens`](/docs/reference/python/api/types/#tokens)

#### Examples

```python title="Root signin (sync)"
token = db.signin({
    "username": "root",
    "password": "root",
})
```

```python title="Root signin (async)"
token = await db.signin({
    "username": "root",
    "password": "root",
})
```

```python title="Scoped signin"
token = db.signin({
    "namespace": "my_namespace",
    "database": "my_database",
    "access": "user_access",
    "email": "user@example.com",
    "password": "s3cret",
})
```

### `.authenticate()` {#authenticate}

Authenticates the current connection with a JWT token.

```python title="Method Syntax"
db.authenticate(token)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>token</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The JWT token to authenticate with.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.authenticate("eyJhbGciOiJIUzI1NiIs...")
```

```python title="Asynchronous"
await db.authenticate("eyJhbGciOiJIUzI1NiIs...")
```

### `.invalidate()` {#invalidate}

Invalidates the authentication for the current connection, removing the associated JWT token.

```python title="Method Syntax"
db.invalidate()
```

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.invalidate()
```

```python title="Asynchronous"
await db.invalidate()
```

### `.info()` {#info}

Returns the record of the currently authenticated user.

```python title="Method Syntax"
db.info()
```

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
user = db.info()
print(user)  # e.g. {"id": "users:john", "email": "john@example.com"}
```

```python title="Asynchronous"
user = await db.info()
```

---

## Variables

### `.let()` {#let}

Defines a variable on the current connection that can be used in subsequent queries.

```python title="Method Syntax"
db.let(key, value)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>key</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The name of the variable (without the <code>$</code> prefix).</td>
        </tr>
        <tr>
            <td><code>value</code> _(required)_</td>
            <td><code><a href="/docs/reference/python/api/types/#value">Value</a></code></td>
            <td>The value to assign to the variable.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.let("user_id", RecordID("users", "john"))
result = db.query("SELECT * FROM users WHERE id = $user_id").first()
```

```python title="Asynchronous"
await db.let("user_id", RecordID("users", "john"))
result = await db.query("SELECT * FROM users WHERE id = $user_id").first()
```

### `.unset()` {#unset}

Removes a previously defined variable from the current connection.

```python title="Method Syntax"
db.unset(key)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>key</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The name of the variable to remove.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.unset("user_id")
```

```python title="Asynchronous"
await db.unset("user_id")
```

---

## Query methods

### `.query()` {#query}

Builds a set of [SurrealQL](/docs/reference/query-language.md) statements to run against the database. Returns an awaitable (async) or lazy (sync) builder — nothing is sent until you trigger it.

```python title="Method Syntax"
db.query(query, vars)
```

> [!IMPORTANT]
> **Behaviour change in v3.0.** `.query()` no longer returns a result directly — it returns a builder that you trigger explicitly with `.execute()`, `.first()` or `.into(cls)`. `.execute()` returns a `list[Value]` with **one entry per statement, always** — even when the query contains a single statement. This surfaces every statement result, fixing the silent-discard behaviour reported in [issue #232](https://github.com/surrealdb/surrealdb.py/issues/232). Use `.first()` when you only care about the first statement's result.

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>query</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The SurrealQL query string to execute.</td>
        </tr>
        <tr>
            <td><code>vars</code> _(optional)_</td>
            <td><code>dict[str, <a href="/docs/reference/python/api/types/#value">Value</a>] | None</code></td>
            <td>Variables to bind into the query. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** a builder. Nothing is sent to the database until you trigger it with one of the accessors below.

| Accessor | Returns |
|---|---|
| `.execute()` | `list[Value]` — one entry per statement, **always a list**, even for a single statement. See [Value](/docs/reference/python/api/types/#value). |
| `.first()` | The first statement's result, or `None` when the query contains no statements. |
| `.into(cls)` | The N statement results mapped positionally onto the fields of a dataclass (or any class accepting keyword arguments). |
| `.into(cls, rows=True)` | `list[cls]` — each **row** of the first statement's result mapped onto `cls`. |

On an async connection every accessor is awaitable — `await db.query(...).execute()`, `await db.query(...).first()`, `await db.query(...).into(Stats)` — and the builder itself is too, so `await db.query(...)` is shorthand for `await db.query(...).execute()`. The sync builder has no such shortcut: you must call an accessor.

> [!NOTE]
> A single-statement `SELECT` without `ONLY` produces **two** levels of nesting, and only the outer one comes from the SDK. The outer list is the per-statement envelope described above; the inner list is SurrealQL's own result set, because `SELECT ... FROM person:tobie` returns an *array of matching rows* even when it targets one record. Use [`ONLY`](/docs/reference/query-language/statements/select.md#the-only-clause) to collapse the inner list server-side, and `.first()` to peel the outer one.
>
> ```python
> db.query("SELECT name FROM person:tobie").execute()            # [[{'name': 'Tobie'}]]
> db.query("SELECT name FROM person:tobie").first()              # [{'name': 'Tobie'}]
> db.query("SELECT VALUE name FROM person:tobie").first()        # ['Tobie']
> db.query("SELECT name FROM ONLY person:tobie").first()         # {'name': 'Tobie'}
> db.query("SELECT VALUE name FROM ONLY person:tobie").first()   # 'Tobie'
> ```

#### Examples

```python title="Single statement (async)"
result = await db.query(
    "SELECT * FROM users WHERE age > $min_age",
    {"min_age": 18},
).execute()
# [[{'id': RecordID(table_name=users, record_id='tobie'), 'age': 30}]]
#  ^ one entry, because the query has one statement

users = await db.query(
    "SELECT * FROM users WHERE age > $min_age",
    {"min_age": 18},
).first()
# [{'id': RecordID(table_name=users, record_id='tobie'), 'age': 30}]
```

```python title="Multi-statement: one entry per statement"
people, count = await db.query(
    "SELECT * FROM person; SELECT count() FROM person GROUP ALL"
).execute()
```

```python title="Map results onto a dataclass"
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)
```

```python title="Synchronous lazy builder"
# The sync builder never auto-executes - it has no __len__, __iter__ or
# __getitem__. Always call an accessor, including for fire-and-forget
# statements.
builder = db.query("SELECT * FROM users")   # nothing has run yet
people = builder.first()
print(len(people))

db.query("DELETE temp_data;").execute()
```

### `.query_raw()` {#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.

```python title="Method Syntax"
db.query_raw(query, vars)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>query</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The SurrealQL query string to execute.</td>
        </tr>
        <tr>
            <td><code>vars</code> _(optional)_</td>
            <td><code>dict[str, <a href="/docs/reference/python/api/types/#value">Value</a>] | None</code></td>
            <td>Variables to bind into the query. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** `dict[str, Any]` — the RPC envelope. Its `result` key holds one entry per statement, each with `status`, `time`, and `result`.

#### Examples

```python title="Synchronous"
raw = db.query_raw(
    "CREATE users SET name = $name; SELECT * FROM users;",
    {"name": "John"},
)

for statement in raw["result"]:
    print(statement["status"], statement["time"])
```

```python title="Asynchronous"
raw = await db.query_raw(
    "CREATE users SET name = $name; SELECT * FROM users;",
    {"name": "John"},
)
```

---

## CRUD methods

> [!IMPORTANT]
> **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:
>
> - `.content(data)` -> `... CONTENT $data`
> - `.replace(data)` -> `... REPLACE $data`
> - `.merge(data)`   -> `... MERGE $data`
> - `.patch(data)`   -> `... PATCH $data`
>
> 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()` {#select}

Selects all records in a table, or a specific record by its ID.

```python title="Method Syntax"
db.select(record)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>record</code> _(required)_</td>
            <td><code><a href="/docs/reference/python/api/types/#recordidtype">RecordIdType</a></code></td>
            <td>A table name (<code>str</code>) or a <code>RecordID</code> to select.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
users = db.select("users")

user = db.select(RecordID("users", "john"))
```

```python title="Asynchronous"
users = await db.select("users")

user = await db.select(RecordID("users", "john"))
```

### `.create()` {#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.

```python title="Method Syntax"
db.create(record, data)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>record</code> _(required)_</td>
            <td><code><a href="/docs/reference/python/api/types/#recordidtype">RecordIdType</a></code></td>
            <td>The table name or <code>RecordID</code> to create.</td>
        </tr>
        <tr>
            <td><code>data</code> _(optional)_</td>
            <td><code><a href="/docs/reference/python/api/types/#value">Value</a> | None</code></td>
            <td>The record data. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
user = db.create("users", {
    "name": "John",
    "email": "john@example.com",
})

product = db.create(RecordID("products", "apple"), {
    "name": "Apple",
    "price": 1.50,
})
```

```python title="Asynchronous"
user = await db.create("users", {
    "name": "John",
    "email": "john@example.com",
})
```

### `.update()` {#update}

Replaces the entire record with the given data. Fields not present in `data` are removed.

```python title="Method Syntax"
db.update(record, data)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>record</code> _(required)_</td>
            <td><code><a href="/docs/reference/python/api/types/#recordidtype">RecordIdType</a></code></td>
            <td>The table name or <code>RecordID</code> to update.</td>
        </tr>
        <tr>
            <td><code>data</code> _(optional)_</td>
            <td><code><a href="/docs/reference/python/api/types/#value">Value</a> | None</code></td>
            <td>The new record data. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
db.update(RecordID("users", "john"), {
    "name": "John Doe",
    "email": "john.doe@example.com",
})
```

```python title="Asynchronous"
await db.update(RecordID("users", "john"), {
    "name": "John Doe",
    "email": "john.doe@example.com",
})
```

### `.upsert()` {#upsert}

Updates an existing record or creates a new one if it does not exist. Replaces the entire record content.

```python title="Method Syntax"
db.upsert(record, data)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>record</code> _(required)_</td>
            <td><code><a href="/docs/reference/python/api/types/#recordidtype">RecordIdType</a></code></td>
            <td>The table name or <code>RecordID</code> to upsert.</td>
        </tr>
        <tr>
            <td><code>data</code> _(optional)_</td>
            <td><code><a href="/docs/reference/python/api/types/#value">Value</a> | None</code></td>
            <td>The record data. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
db.upsert(RecordID("users", "john"), {
    "name": "John",
    "email": "john@example.com",
})
```

```python title="Asynchronous"
await db.upsert(RecordID("users", "john"), {
    "name": "John",
    "email": "john@example.com",
})
```

### `.merge` clause {#merge}

`.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`.

```python title="Synchronous"
db.update(RecordID("users", "john")).merge({"age": 32})
```

```python title="Asynchronous"
await db.update(RecordID("users", "john")).merge({"age": 32})
```

### `.patch` clause {#patch}

`.patch(data)` is a builder clause method - chain it on `.update()`, `.upsert()`, or `.create()`. It compiles to `... PATCH $data` and applies JSON Patch operations.

```python title="Synchronous"
db.update(RecordID("users", "john")).patch([
    {"op": "replace", "path": "/email", "value": "new@example.com"},
    {"op": "add", "path": "/verified", "value": True},
])
```

```python title="Asynchronous"
await db.update(RecordID("users", "john")).patch([
    {"op": "replace", "path": "/email", "value": "new@example.com"},
])
```

### `.delete()` {#delete}

Deletes all records in a table, or a specific record by its ID.

```python title="Method Syntax"
db.delete(record)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>record</code> _(required)_</td>
            <td><code><a href="/docs/reference/python/api/types/#recordidtype">RecordIdType</a></code></td>
            <td>The table name or <code>RecordID</code> to delete.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
db.delete(RecordID("users", "john"))

db.delete("temp_data")
```

```python title="Asynchronous"
await db.delete(RecordID("users", "john"))
```

---

## Insert methods

### `.insert()` {#insert}

Inserts one or more records into a table.

```python title="Method Syntax"
db.insert(table, data)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>table</code> _(required)_</td>
            <td><code>str | Table</code></td>
            <td>The table to insert into.</td>
        </tr>
        <tr>
            <td><code>data</code> _(required)_</td>
            <td><code><a href="/docs/reference/python/api/types/#value">Value</a></code></td>
            <td>A single record dict or a list of record dicts to insert.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
db.insert("users", {"name": "Alice", "email": "alice@example.com"})

db.insert("users", [
    {"name": "Bob", "email": "bob@example.com"},
    {"name": "Charlie", "email": "charlie@example.com"},
])
```

```python title="Asynchronous"
await db.insert("users", {"name": "Alice", "email": "alice@example.com"})
```

### Inserting relations {#insert-relation}

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.

```python title="Synchronous"
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"),
})
```

```python title="Asynchronous"
await db.insert("likes", {
    "in": RecordID("users", "alice"),
    "out": RecordID("posts", "post1"),
}, relation=True)
```

---

## Calling functions

### `.run()` {#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.

```python title="Method Syntax"
db.run(name, args, version)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>name</code> _(required)_</td>
            <td><code>str</code></td>
            <td>The fully-qualified function name, e.g. <code>"fn::increment"</code>.</td>
        </tr>
        <tr>
            <td><code>args</code> _(optional)_</td>
            <td><code>list[<a href="/docs/reference/python/api/types/#value">Value</a>] | None</code></td>
            <td>Positional arguments forwarded to the function.</td>
        </tr>
        <tr>
            <td><code>version</code> _(optional)_</td>
            <td><code>str | None</code></td>
            <td>Optional function version selector.</td>
        </tr>
    </tbody>
</table>

**Returns:** [`Value`](/docs/reference/python/api/types/#value)

#### Examples

```python title="Synchronous"
result = db.run("fn::increment", [1])
```

```python title="Asynchronous"
greeting = await db.run("fn::greet", ["world"])
```

---

## Live queries

> [!NOTE]
> Live queries require a WebSocket connection (`ws://` or `wss://`). HTTP and embedded connections raise `UnsupportedFeatureError`.

### `.live()` {#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()`.

```python title="Method Syntax"
db.live(table, diff)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>table</code> _(required)_</td>
            <td><code>str | Table</code></td>
            <td>The table to watch for changes.</td>
        </tr>
        <tr>
            <td><code>diff</code> _(optional)_</td>
            <td><code>bool</code></td>
            <td>If <code>True</code>, notifications include JSON Patch diffs instead of full records. Defaults to <code>False</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** `UUID`

#### Examples

```python title="Synchronous"
query_uuid = db.live("users")

query_uuid = db.live("users", diff=True)
```

```python title="Asynchronous"
query_uuid = await db.live("users")
```

### `.subscribe_live()` {#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.

```python title="Method Syntax"
db.subscribe_live(query_uuid)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>query_uuid</code> _(required)_</td>
            <td><code>str | UUID</code></td>
            <td>The UUID of the live query returned by <a href="#live"><code>.live()</code></a>.</td>
        </tr>
    </tbody>
</table>

**Returns (sync):** `Generator[dict[str, Value], None, None]`
**Returns (async):** `AsyncGenerator[dict[str, Value], None]`

#### Examples

```python title="Synchronous"
query_uuid = db.live("users")

for notification in db.subscribe_live(query_uuid):
    print(notification["action"], notification["result"])
```

```python title="Asynchronous"
query_uuid = await db.live("users")

async for notification in db.subscribe_live(query_uuid):
    print(notification["action"], notification["result"])
```

### `.kill()` {#kill}

Terminates a running live query by its UUID.

```python title="Method Syntax"
db.kill(query_uuid)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>query_uuid</code> _(required)_</td>
            <td><code>str | UUID</code></td>
            <td>The UUID of the live query to kill.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.kill(query_uuid)
```

```python title="Asynchronous"
await db.kill(query_uuid)
```

---

## Sessions

> [!NOTE]
> 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()` {#new-session}

Creates a new isolated session on the current connection.

```python title="Method Syntax"
db.new_session()
```

**Returns (sync):** `BlockingSurrealSession`
**Returns (async):** `AsyncSurrealSession`

#### Examples

```python title="Synchronous"
session = db.new_session()
session.use("other_ns", "other_db")
result = session.select("users")
```

```python title="Asynchronous"
session = await db.new_session()
await session.use("other_ns", "other_db")
result = await session.select("users")
```

### `.attach()` {#attach}

Attaches to the server-side session associated with this connection and returns its session ID.

```python title="Method Syntax"
db.attach()
```

**Returns:** `UUID`

#### Examples

```python title="Synchronous"
session_id = db.attach()
```

```python title="Asynchronous"
session_id = await db.attach()
```

### `.detach()` {#detach}

Detaches from a server-side session.

```python title="Method Syntax"
db.detach(session_id)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>session_id</code> _(required)_</td>
            <td><code>UUID</code></td>
            <td>The session ID to detach from.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
db.detach(session_id)
```

```python title="Asynchronous"
await db.detach(session_id)
```

---

## Transactions

> [!NOTE]
> 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()` {#begin}

Begins a new transaction, optionally within a specific session.

```python title="Method Syntax"
db.begin(session_id)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>session_id</code> _(optional)_</td>
            <td><code>UUID | None</code></td>
            <td>The session to start the transaction in. If <code>None</code>, uses the default session. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** `UUID` — the transaction ID

#### Examples

```python title="Synchronous"
txn_id = db.begin()
```

```python title="Asynchronous"
txn_id = await db.begin()
```

```python title="Within a session"
session_id = db.attach()
txn_id = db.begin(session_id)
```

### `.commit()` {#commit}

Commits a transaction, applying all changes made within it.

```python title="Method Syntax"
db.commit(txn_id, session_id)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>txn_id</code> _(required)_</td>
            <td><code>UUID</code></td>
            <td>The transaction ID returned by <a href="#begin"><code>.begin()</code></a>.</td>
        </tr>
        <tr>
            <td><code>session_id</code> _(optional)_</td>
            <td><code>UUID | None</code></td>
            <td>The session the transaction belongs to. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
txn_id = db.begin()
db.query("CREATE users SET name = 'Alice'").execute()
db.commit(txn_id)
```

```python title="Asynchronous"
txn_id = await db.begin()
await db.query("CREATE users SET name = 'Alice'").execute()
await db.commit(txn_id)
```

### `.cancel()` {#cancel}

Cancels a transaction, discarding all changes made within it.

```python title="Method Syntax"
db.cancel(txn_id, session_id)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>txn_id</code> _(required)_</td>
            <td><code>UUID</code></td>
            <td>The transaction ID returned by <a href="#begin"><code>.begin()</code></a>.</td>
        </tr>
        <tr>
            <td><code>session_id</code> _(optional)_</td>
            <td><code>UUID | None</code></td>
            <td>The session the transaction belongs to. Defaults to <code>None</code>.</td>
        </tr>
    </tbody>
</table>

**Returns:** `None`

#### Examples

```python title="Synchronous"
txn_id = db.begin()
db.query("DELETE users").execute()
db.cancel(txn_id)
```

```python title="Asynchronous"
txn_id = await db.begin()
await db.query("DELETE users").execute()
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

```python title="Synchronous context manager"
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

```python title="Asynchronous context manager"
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

```python title="Full workflow (sync)"
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},
    ).first()
    print("Affordable:", cheap)

    db.update(RecordID("products", products[0]["id"].id)).merge({"stock": 50})

    db.delete(RecordID("products", products[1]["id"].id))
```

```python title="Full workflow (async)"
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](/docs/reference/python/api/core/surreal-session.md) — Session management reference
- [SurrealTransaction](/docs/reference/python/api/core/surreal-transaction.md) — Transaction reference
- [Data types](/docs/reference/python/api/types.md) — Type aliases and value types
- [Errors](/docs/reference/python/api/errors.md) — Error classes reference
- [Connecting to SurrealDB](/docs/reference/python/concepts/connecting-to-surrealdb.md) — Connection protocols and patterns
