> Full SurrealDB documentation index: https://surrealdb.com/docs/llms.txt

# Environment variables

Every SURREAL_ variable, with its default and allowed values.

Environment variables can be used to tailor the behaviour of a running SurrealDB instance.

Environment variables are divided into four types:

* **SurrealDB environment variables**: environment variables that pertain to the overall running of a SurrealDB server. Example: `SURREAL_DEFAULT_DATABASE`. Includes an [operator and internal config](#operator-and-internal-config) subsection for advanced settings.
* **Command environment variables**: environment variables that can be used in lieu of a command flag. Example: `SURREAL_CAPS_ALLOW_ALL=true surreal db start`, equivalent to `surreal db start --allow-all`.
* **Storage backend environment variables**: environment variables that pertain to a certain storage backend. Example: `SURREAL_SURREALKV_ENABLE_VLOG`.
* **SurrealDB Cloud environment variables**: environment variables that are set via the [Configure instance](/docs/manage/instances/configure.md) sidebar for a SurrealDB Cloud instance.

> [!IMPORTANT]
> Every variable on this page belongs to the database and starts with `SURREAL_`. They are read by `surreal db`, and by the server in a container that runs `surreal start` directly. The launcher has its own variables, which start with `SURREAL_CLI_` and are documented in the [launcher reference](/docs/reference/cli/launcher.md). The `surreal cloud` component reads `SURREAL_CLOUD_*` variables, described in the [Cloud reference](/docs/reference/cli/cloud.md). The prefixes are kept apart deliberately: a database credential such as `SURREAL_TOKEN` is not a Cloud credential, and must not be sent to the SurrealDB Cloud API.

Many environment variables have a maximum value equivalent to the greatest possible `usize`, which is an unsigned integer with a number of bytes depending on the target that the database runs on. For most systems this will be 64 bits, leading to a maximum size of 18_446_744_073_709_551_615 (2<sup>64</sup>), while for 32 bits the maximum will be 4_294_967_296 (2<sup>32</sup>).

## Byte size suffixes

_(since v3.0.0)_

Environment variables that set a size in bytes, such as `SURREAL_HTTP_MAX_SQL_BODY_SIZE` and `SURREAL_WEBSOCKET_MAX_MESSAGE_SIZE`, accept either a raw byte count or a number with a suffix. Suffixes are case-insensitive, and all of them are powers of 1024, so `4GB` and `4GiB` both mean 4,294,967,296 bytes.

| Suffix | Multiplier |
| ------ | ---------- |
| none, `b` | 1 |
| `k`, `kb`, `kib` | 1024 |
| `m`, `mb`, `mib` | 1024<sup>2</sup> |
| `g`, `gb`, `gib` | 1024<sup>3</sup> |

> [!WARNING]
> A value that cannot be parsed is discarded and the default is used instead - the server does not fail to start. On 2.x these variables take a raw byte count only, so a suffixed value such as `16MiB` is silently ignored there and the default remains in effect.

## SurrealDB environment variables

These environment variables can be used to configure a SurrealDB server to configure areas such as the HTTP server and client, limits, telemetry, and so on.

### Batch config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NORMAL_FETCH_SIZE</code></td>
      <td scope="row" data-label="Default">500</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of keys that should be scanned at once in general queries. Read only before 3.1.0; later versions use a fixed batch of 500.</td>
    </tr>
        <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_EXPORT_BATCH_SIZE</code></td>
      <td scope="row" data-label="Default">1000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of keys that should be scanned at once for export queries.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_COUNT_BATCH_SIZE</code>_(since v2.2.0)_</td>
      <td scope="row" data-label="Default">50,000 (10,000 on 2.x)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of keys that should be scanned at once for count queries. Read only before 3.1.0; later versions use a fixed batch of 50,000.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_INDEXING_BATCH_SIZE</code></td>
      <td scope="row" data-label="Default">250</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of keys to scan at once per concurrent indexing batch. Read only before 3.1.0; later versions use a fixed batch of 250.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TABLE_DOC_IDS_BATCH_SIZE</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">1000</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">The number of document ids allocated at once from a table's shared document id sequence, which full-text, HNSW and DiskANN indexes use. Larger batches reduce coordination on the distributed sequence, at the cost of larger gaps in the ids when a node is lost before it uses up its current batch. Replaces <code>SURREAL_FTS_DOC_IDS_BATCH_SIZE</code>, which 3.3.0 no longer reads.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRAPH_FOLD_BATCH</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">1024</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How many graph adjacency keys one background fold pass packs into blocks per transaction. This bounds the transaction size on a vertex with many edges, which is then folded over several passes. See <code>SURREAL_GRAPH_FOLD_INTERVAL</code>.</td>
    </tr>
  </tbody>
</table>

### Cache config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TRANSACTION_CACHE_SIZE</code></td>
      <td scope="row" data-label="Default">512 (10,000 before 3.1.0)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Specifies the number of items which can be cached within a single transaction.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATASTORE_CACHE_SIZE</code></td>
      <td scope="row" data-label="Default">1,000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of definitions which can be cached across transactions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HNSW_CACHE_SIZE</code></td>
      <td scope="row" data-label="Default">268,435,456 (256 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum total size, in bytes, of the HNSW vector cache, shared across all HNSW indexes in the process. This bounds the cached element <em>vectors</em> used for distance computation - it is not a cap on total HNSW memory: the adjacency graph is loaded into resident memory on first use and stays there, outside this budget. Contrast <code>SURREAL_DISKANN_CACHE_SIZE</code>, which does page graph structure.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DISKANN_CACHE_SIZE</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">268,435,456 (256 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum total size, in bytes, of the DISKANN index cache, shared across all DISKANN indexes in the process. DISKANN graph data lives in the key-value store and is paged through this bounded cache. The DISKANN counterpart of <code>SURREAL_HNSW_CACHE_SIZE</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRAPH_RESOLVE_CACHE_SIZE</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">67,108,864 (64 MiB)</td>
      <td scope="row" data-label="Allowed values">A u64</td>
      <td scope="row" data-label="Notes">The maximum total size, in bytes, of the cache that maps document ids back to record keys when a traversal reads numeric-encoded graph adjacency entries. Only relevant once <code>SURREAL_GRAPH_NUMERIC_IDS</code> has written numeric blocks.</td>
    </tr>
  </tbody>
</table>

### File config

Server-side filesystem access for features that read paths from disk (notably the `mapper()` filter and the `segment()` tokenizer on [`DEFINE ANALYZER`](/docs/reference/query-language/statements/define/analyzer.md)). This is separate from `SURREAL_BUCKET_FOLDER_ALLOWLIST` (below), which gates the experimental [files](/docs/learn/schema-management/files/buckets.md) feature.

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
  <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_FILE_ALLOWLIST</code></td>
      <td scope="row" data-label="Default">none (deny all)</td>
      <td scope="row" data-label="Allowed values">Colon-separated paths on Unix; semicolon-separated on Windows</td>
      <td scope="row" data-label="Notes">Directories the server may read when an analyzer uses <code>mapper('&lt;path&gt;')</code>. An empty or unset value denies every path. Each mapper file must resolve under one of the listed directories. See <a href="/docs/reference/query-language/statements/define/analyzer.md#mapperpath">DEFINE ANALYZER - mapper</a>.</td>
    </tr>
  <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SEGMENT_DICTIONARY_PATH</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">none (use the dictionaries built into the binary)</td>
      <td scope="row" data-label="Allowed values">A path to a directory</td>
      <td scope="row" data-label="Notes">Directory holding the morphological dictionaries the <code>segment(&lt;language&gt;)</code> tokenizer reads, one subdirectory per language: <code>chinese</code>, <code>japanese</code>, <code>korean</code>. The released binaries already carry all three, so this is only needed to replace them with a custom or updated dictionary, or for a build made without them. Each language is overridden only if the directory holds a dictionary for it; the rest keep using the built-in one. See <a href="/docs/reference/query-language/statements/define/analyzer.md#segmentlanguage">DEFINE ANALYZER - segment</a>.</td>
    </tr>
  <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_BUCKET_FOLDER_ALLOWLIST</code></td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">Comma-separated paths</td>
      <td scope="row" data-label="Notes">Specifies a list of paths in which files can be accessed.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GLOBAL_BUCKET</code></td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">Specifies the name of a global bucket for file data.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GLOBAL_BUCKET_ENFORCED</code></td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to enforce a global bucket for file data.</td>
    </tr>
  </tbody>
</table>

### HTTP client config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>

  <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_HTTP_REDIRECTS</code></td>
      <td scope="row" data-label="Default">10</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of HTTP redirects allowed within http functions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_HTTP_IDLE_CONNECTIONS_PER_HOST</code></td>
      <td scope="row" data-label="Default">128</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of idle HTTP connections to maintain per host.</td>
    </tr>
        <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_HTTP_IDLE_CONNECTIONS</code></td>
      <td scope="row" data-label="Default">1000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of idle HTTP connections to maintain. Has no effect: earlier versions read the value without applying it to the HTTP client, and 3.3.0 no longer reads it. Use <code>SURREAL_MAX_HTTP_IDLE_CONNECTIONS_PER_HOST</code> instead.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_IDLE_TIMEOUT_SECS</code></td>
      <td scope="row" data-label="Default">90</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The timeout for idle HTTP connections before closing.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_CONNECT_TIMEOUT_SECS</code></td>
      <td scope="row" data-label="Default">30</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The timeout for connecting to HTTP endpoints.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALDB_USER_AGENT</code></td>
      <td scope="row" data-label="Default">SurrealDB</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The USER-AGENT string used by HTTP requests. Before 3.1.0 this variable was named <code>SURREAL_USER_AGENT</code>, which later versions ignore.</td>
    </tr>
  </tbody>
</table>

### HTTP server config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>

<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NET_MAX_CONCURRENT_REQUESTS</code></td>
      <td scope="row" data-label="Default">1,048,576</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How many concurrent network requests can be handled at once</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_ML_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">4,294,967,296 (4 GiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP /ml endpoints. Counted cumulatively across the whole request, not per chunk.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_MCP_BODY_SIZE</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">4,194,304 (4 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP <code>/mcp</code> endpoint. See [Embedded MCP](/docs/build/ai-agents/mcp/embedded.md).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_SQL_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">1,048,576 (1 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP /sql endpoint</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_GQL_BODY_SIZE</code>_(since v3.2.0)_</td>
      <td scope="row" data-label="Default">1,048,576 (1 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP <code>/gql</code> endpoint. See <a href="/docs/learn/querying/gql/via-http.md">GQL via HTTP</a>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_API_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">4,194,304 (4 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum HTTP body size of the HTTP /api endpoint.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_RPC_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">4,194,304 (4 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP /rpc endpoint.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRPC_MAX_MESSAGE_SIZE</code></td>
      <td scope="row" data-label="Default">The value of <code>SURREAL_HTTP_MAX_RPC_BODY_SIZE</code>, so 4,194,304 (4 MiB) unless that is raised</td>
      <td scope="row" data-label="Allowed values">A usize, clamped to a ceiling of 4,294,967,295 (4 GiB less one byte), the largest size a gRPC length prefix can express. A value below the floor needed to carry one streaming file chunk is raised to it.</td>
      <td scope="row" data-label="Notes">From 3.3.0. The largest single gRPC message the server will accept or emit, also reported to clients as <code>Limits.max_message_bytes</code>. This is the gRPC counterpart of <code>SURREAL_WEBSOCKET_MAX_MESSAGE_SIZE</code>: raise it for a transaction that writes a large batch in one request.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRPC_MAX_ATTACHED_SESSIONS</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">16384</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of explicitly attached sessions the gRPC transport keeps at once. The count is for the whole process rather than per connection, because a gRPC channel reconnects transparently and one session's requests can arrive on different connections. Per-request sessions do not count towards it.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRPC_NOTIFICATION_BUFFER</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">1024</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How many live query notifications can be buffered for a gRPC subscription whose client is not keeping up. When the buffer is full, the server ends that subscription with a <code>RESOURCE_EXHAUSTED</code> status instead of waiting.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_KEY_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">16,384 (16 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP /key endpoints</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_SIGNUP_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">1024 (1 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP /signup endpoint.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_IMPORT_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">4,294,967,296 (4 GiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum HTTP body size of the HTTP <code>/import</code> endpoint. Counted cumulatively across the whole request, not per chunk. Also enforced on the gRPC import stream. See [Request size limits](/docs/reference/rest-api/http-protocol.md#request-size-limits).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_MAX_SIGNIN_BODY_SIZE</code></td>
      <td scope="row" data-label="Default">1024 (1 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum HTTP body size of the HTTP /signin endpoints</td>
    </tr>
  </tbody>
</table>

> [!NOTE]
> Before SurrealDB 3.3.0, `SURREAL_HTTP_MAX_SIGNUP_BODY_SIZE` and `SURREAL_HTTP_MAX_SIGNIN_BODY_SIZE` were applied to each other's endpoint. Both default to 1 KiB, so no default deployment was affected, but raising one of them had no effect on the endpoint it names and the other endpoint kept returning `413 Payload Too Large`. If you worked around this by tuning the opposite variable, move the value back to the one that matches the endpoint.

### MCP config

_(since v3.1.0)_

Used by the built-in [Model Context Protocol](/docs/build/ai-agents/mcp/embedded.md) server (`/mcp` on `surreal db start`, `surreal db mcp` on stdio). Stdio namespace/database selection uses `SURREAL_MCP_NS` and `SURREAL_MCP_DB` on the [`mcp`](/docs/reference/cli/db/commands/mcp.md) subcommand.

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_QUERY_TIMEOUT_SECS</code></td>
      <td scope="row" data-label="Default">60</td>
      <td scope="row" data-label="Allowed values">Seconds (integer); <code>0</code> disables</td>
      <td scope="row" data-label="Notes">Outer timeout on each MCP tool execution.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_MAX_RESULT_BYTES</code></td>
      <td scope="row" data-label="Default">262,144 (256 KiB)</td>
      <td scope="row" data-label="Allowed values">Bytes (integer); <code>0</code> disables</td>
      <td scope="row" data-label="Notes">Maximum serialised tool / resource response size; larger results are truncated with a marker.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_RUN_MAX_ARGS</code></td>
      <td scope="row" data-label="Default">64</td>
      <td scope="row" data-label="Allowed values">A positive integer</td>
      <td scope="row" data-label="Notes">Maximum arguments for a single <code>run</code> tool call.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_PARAMS_MAX_KEYS</code></td>
      <td scope="row" data-label="Default">256</td>
      <td scope="row" data-label="Allowed values">A positive integer</td>
      <td scope="row" data-label="Notes">Maximum top-level keys in MCP parameter / data objects.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_PARAMS_MAX_QL_BYTES</code></td>
      <td scope="row" data-label="Default">4,096 (4 KiB)</td>
      <td scope="row" data-label="Allowed values">A positive integer; values ≤ 0 fall back to the default</td>
      <td scope="row" data-label="Notes">Maximum byte length of a single <code>$ql</code> SurrealQL pass-through string inside a <code>*_data</code> payload.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_SCHEMA_RESOURCE_MAX_TABLES</code></td>
      <td scope="row" data-label="Default">200</td>
      <td scope="row" data-label="Allowed values">A positive integer; values ≤ 0 fall back to the default</td>
      <td scope="row" data-label="Notes">Maximum tables the database-level schema resource enriches with per-table fields / indexes / events. Tables beyond the cap keep a bare <code>DEFINE TABLE</code> and the body includes a <code>tables_truncated_at</code> marker.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_ALLOWED_HOSTS</code> _(since v3.2.1)_</td>
      <td scope="row" data-label="Default">loopback only (<code>localhost</code>, <code>127.0.0.1</code>, <code>::1</code>)</td>
      <td scope="row" data-label="Allowed values">Comma-separated exact hostnames</td>
      <td scope="row" data-label="Notes">Hostnames accepted in the HTTP <code>Host</code> header for <code>/mcp</code> (DNS-rebinding guard). A non-empty list <strong>replaces</strong> the loopback default, so include <code>localhost</code> yourself if you still need it. Entries without a port match any port. Ignored when <code>SURREAL_MCP_ALLOW_ALL_HOSTS</code> is set.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MCP_ALLOW_ALL_HOSTS</code> _(since v3.2.1)_</td>
      <td scope="row" data-label="Default"><code>false</code></td>
      <td scope="row" data-label="Allowed values"><code>true</code> / <code>1</code> to enable</td>
      <td scope="row" data-label="Notes">Disables the <code>Host</code>-header allowlist (accept any <code>Host</code>). Escape hatch for a trusted proxy or load balancer. Takes precedence over <code>SURREAL_MCP_ALLOWED_HOSTS</code>.</td>
    </tr>
  </tbody>
</table>

### GQL config

_(since v3.2.0)_

Resource limits for [ISO GQL (Cypher Query Language)](/docs/learn/querying/gql/overview.md) `MATCH` execution. Errors name the limit when it is exceeded. From **3.3.0**, GQL is enabled by default; on **3.2.x**, enable it with [`--allow-experimental gql`](/docs/reference/cli/db/commands/start.md#experimental-capabilities).

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GQL_MAX_PATH_ROWS</code></td>
      <td scope="row" data-label="Default">1,000,000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Per source row, bounds live and emitted rows during variable-length path expansion in a GQL <code>MATCH</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GQL_MAX_JOIN_BUILD_ROWS</code></td>
      <td scope="row" data-label="Default">1,000,000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Bounds the in-memory build side of hash joins between GQL match patterns (and distinct-operator working sets).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GQL_MAX_OUTPUT_ROWS</code></td>
      <td scope="row" data-label="Default">1,000,000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Bounds cumulative rows emitted by GQL hash-join operators (including cross joins).</td>
    </tr>
  </tbody>
</table>

### Limits config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>

    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRAPH_INLINE_PROPS_CAP</code> _(since v3.3.0)_</td>
      <td scope="row" data-label="Default">64</td>
      <td scope="row" data-label="Allowed values">A number of bytes, without a unit suffix</td>
      <td scope="row" data-label="Notes">Largest encoded payload an <a href="/docs/reference/query-language/statements/define/field.md#using-inline-to-filter-a-traversal-during-the-scan"><code>INLINE</code></a> field set may occupy inside a graph adjacency entry. A larger payload spills, leaving the values on the edge record only.</td>
    </tr>

    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_BITMAP_BRANCH_BUDGET</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">250,000</td>
      <td scope="row" data-label="Allowed values">A usize; <code>0</code> disables the budget</td>
      <td scope="row" data-label="Notes">How many index entries one range branch of a bitmap plan, which combines several indexes into a bitmap of candidate records, may read before that branch is abandoned. The abandoned branch's condition is then checked as an ordinary <code>WHERE</code> filter, so an unselective range cannot make the bitmap plan slower than scanning. The same budget bounds the allow-list built for a pre-filtered vector search (see <a href="#vector-search-config">Vector search config</a>).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_EXTERNAL_SORTING_BUFFER_LIMIT</code></td>
      <td scope="row" data-label="Default">50000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of result records which will trigger on-disk sorting.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_STRING_SIMILARITY_LIMIT</code></td>
      <td scope="row" data-label="Default">16384</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum input string length for similarity/distance functions</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_FAN_OUT_ROW_THRESHOLD</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">4</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">A batch with fewer items than this is evaluated one item at a time. A larger batch has its items evaluated concurrently, but only when the evaluation is read-only. Set it above the batch size to turn concurrent evaluation off.</td>
    </tr>
     <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GENERATION_ALLOCATION_LIMIT</code></td>
      <td scope="row" data-label="Default">1,048,576</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Limits memory allocation for certain built-in functions (e.g., string::replace) to avoid uncontrolled memory usage. Default is 1,048,576 bytes (computed as 2<sup>20</sup>).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_IDIOM_RECURSION_LIMIT</code></td>
      <td scope="row" data-label="Default">256</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum recursive idiom path depth allowed. Read only before 3.1.0; later versions use a fixed limit of 256.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_COMPUTATION_DEPTH</code></td>
      <td scope="row" data-label="Default">120</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Specifies how deep recursive computation will go before erroring.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_CONCURRENT_TASKS</code></td>
      <td scope="row" data-label="Default">64</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Specifies how many concurrent jobs can be buffered in the worker channel.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_EXPRESSION_PARSING_DEPTH</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">128</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How deep the parser will build an expression operator tree. This bounds long operator chains such as <code>1 + 1 + 1 + …</code> and prefix/postfix chains, which consume neither of the other two parsing budgets.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_OBJECT_PARSING_DEPTH</code></td>
      <td scope="row" data-label="Default">100</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How deep the parser will parse nested objects and arrays. Type annotations such as <code>array&lt;option&lt;array&lt;int&gt;&gt;&gt;</code> count against it as well. For data arriving over an SDK or RPC this is the governing limit. For a query written as text, see <a href="#nesting-depth-in-queries-versus-data">Nesting depth in queries versus data</a>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_ORDER_LIMIT_PRIORITY_QUEUE_SIZE</code>_(since v2.2.0)_</td>
      <td scope="row" data-label="Default">1000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum size of the priority queue triggering usage of the priority queue for the result collector.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_QUERY_PARSING_DEPTH</code></td>
      <td scope="row" data-label="Default">20</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How deep the parser will parse recursive queries (queries within queries). Object and array literals written into a query count against this budget as well as against <code>SURREAL_MAX_OBJECT_PARSING_DEPTH</code>, and this one is the smaller of the two - see <a href="#nesting-depth-in-queries-versus-data">Nesting depth in queries versus data</a>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_OPERATOR_BUFFER_SIZE</code></td>
      <td scope="row" data-label="Default">2</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of batches each operator buffers ahead of downstream demand. Set to 0 to disable operator-level pipeline buffering.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_REGEX_SIZE_LIMIT</code></td>
      <td scope="row" data-label="Default">10,485,760 (10 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Limits the maximum allowed size (in bytes) for regular expressions. This prevents excessive memory consumption when building complex or very large regex patterns.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SCAN_BATCH_BYTES</code>_(since v3.3.1)_</td>
      <td scope="row" data-label="Default">2,097,152 (2 MiB)</td>
      <td scope="row" data-label="Allowed values">A byte count, or a size such as <code>512KiB</code></td>
      <td scope="row" data-label="Notes">The approximate decoded size of each batch of records that a query fetches from an index result, such as the matches of a full-text search. A batch also holds at most 1,000 records. Every operator after the scan holds whole batches, so the memory a query uses grows with this value. Lower it to limit memory on a small node, or raise it for fewer, larger batches. <code>0</code> and values that cannot be parsed are ignored.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TRANSACTION_MAX_WRITE_KEYS</code>_(since v3.2.4)_</td>
      <td scope="row" data-label="Default">0 (disabled)</td>
      <td scope="row" data-label="Allowed values">A <code>u64</code>; <code>0</code> disables</td>
      <td scope="row" data-label="Notes">Maximum number of key writes a single statement transaction may buffer before it is aborted and rolled back. Cascaded deletes, full-text index maintenance, graph-edge cleanup, and commit-time changefeed / live-query events all count toward the limit; each range delete counts as one write. Tripping the guard poisons the transaction so an explicit client <code>COMMIT</code> cannot persist a partial statement. Internal maintenance transactions (index builds, compaction, GC) are not bounded. On TiKV, range deletes may expand further inside the storage layer - size distributed clusters with both this limit and <code>SURREAL_TIKV_DELR_MAX_KEYS</code> in mind. Scale / multi-node deployments often use a limit in the 50,000-100,000 range; leave at <code>0</code> for typical single-node use.</td>
    </tr>
  </tbody>
</table>

#### Nesting depth in queries versus data

Four separate budgets bound recursion, and which one a deeply nested value hits depends on how it reaches the server.

A value written into query text is read by the SurrealQL parser, and each level of an object or array costs one level of `SURREAL_MAX_QUERY_PARSING_DEPTH` as well as one of `SURREAL_MAX_OBJECT_PARSING_DEPTH`. Since the query budget defaults to `20` against the object budget's `100`, the query budget is what a nested literal runs out of first.

A value arriving as **data** (the body of an SDK call, an RPC message, or a WebSocket frame) is never parsed as SurrealQL, so it spends only the object budget and nests roughly five times deeper for the same default configuration.

The practical effect is that one document can be accepted through an SDK and rejected as a literal in `surreal db sql`, which reads as an inconsistency but is two budgets doing their own jobs. A structure alternating object and array, as in `{ inner: [{ inner: [ … ] }] }`, spends two levels per step:

| Path | Governing default | Levels of `{ inner: [ … ] }` |
| --- | --- | --- |
| Query text (`surreal db sql`, `/sql`) | `SURREAL_MAX_QUERY_PARSING_DEPTH` = 20 | 9 |
| SDK, RPC, WebSocket | `SURREAL_MAX_OBJECT_PARSING_DEPTH` = 100 | 49 |

Exceeding either is a parse error, not a crash, giving the error `Exceeded query recursion depth limit` for the first, `Exceeded object recursion depth limit` for the second. To send deep literals as text, raise `SURREAL_MAX_QUERY_PARSING_DEPTH` - raising the object budget alone changes nothing on that path.

> [!NOTE]
> Two further depth limits are fixed and cannot be configured: recursive idiom paths stop at 256, and the binary protocol's decoder rejects frames nested beyond 512. Neither is reachable before the parsing budgets above under a default configuration.

### Runtime config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_RUNTIME_MAX_BLOCKING_THREADS</code></td>
      <td scope="row" data-label="Default">512</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Number of threads which can be started for blocking operations.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_RUNTIME_STACK_SIZE</code></td>
      <td scope="row" data-label="Default">10,485,760 (10 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Runtime thread memory stack size. Default stack size is doubled if compiled from source in Debug mode.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_RUNTIME_WORKER_THREADS</code></td>
      <td scope="row" data-label="Default">Number of CPU cores (minimum 4)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Number of runtime worker threads used to start. See <a href="/docs/learn/querying/performance/performance-best-practices.md#cpu-cores-and-concurrent-queries">CPU cores and concurrent queries</a>.</td>
    </tr>
  </tbody>
</table>

### Scripting config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SCRIPTING_MAX_STACK_SIZE</code></td>
      <td scope="row" data-label="Default">262_144 (256 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum stack size of the JavaScript function runtime.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SCRIPTING_MAX_MEMORY_LIMIT</code></td>
      <td scope="row" data-label="Default">2,097,152 (2 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum memory limit of the JavaScript function runtime.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SCRIPTING_MAX_TIME_LIMIT</code></td>
      <td scope="row" data-label="Default">5000 (5000 milliseconds or 5 seconds)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum allowed time in milliseconds that a JavaScript function is allowed to run for.</td>
    </tr>
  </tbody>
</table>

### Security config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_INSECURE_FORWARD_ACCESS_ERRORS</code></td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Forward all signup/signin/authenticate query errors to a client performing authentication. Do not use in production.</td>
    </tr>
  </tbody>
</table>

### Surrealism config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LAZY_SURREALISM</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to lazy-load Surrealism modules instead of eagerly compiling them at server startup.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_CACHE_SIZE</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">100</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of surrealism modules which can be cached across transactions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_MAX_POOL_SIZE</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">8</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Per-module controller pool size ceiling for Surrealism WASM modules. Has no effect: the server does not read this variable, so the ceiling stays at 8.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_MAX_MEMORY</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">None (unlimited)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Per-module WASM linear memory ceiling in bytes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_MAX_EXECUTION_TIME</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">None (unlimited)</td>
      <td scope="row" data-label="Allowed values">A u64 (milliseconds)</td>
      <td scope="row" data-label="Notes">Per-invocation execution time ceiling for Surrealism WASM modules.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_MAX_KV_ENTRIES</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">None (unlimited)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Per-module KV store entry count ceiling.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_MAX_KV_VALUE_BYTES</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">None (unlimited)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Per-module KV store maximum value size in bytes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_LOG_LEVEL</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">debug</td>
      <td scope="row" data-label="Allowed values">none, full, error, warn, info, debug, trace</td>
      <td scope="row" data-label="Notes">Controls the tracing level at which Surrealism module stdout is emitted.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALISM_SILO_ENDPOINT</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default"><code>https://silo.surrealdb.com</code></td>
      <td scope="row" data-label="Allowed values">A URL</td>
      <td scope="row" data-label="Notes">The base URL that a <code>silo::</code> module executable in <a href="/docs/reference/query-language/statements/define/module.md">DEFINE MODULE</a> is fetched from, as <code>{endpoint}/{organisation}/{package}/{major}.{minor}.{patch}.surli</code>. A trailing slash is removed. Set it to a mirror to serve packages from somewhere else.</td>
    </tr>
  </tbody>
</table>

### Telemetry config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TELEMETRY_DISABLE_METRICS</code></td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to disable sending metrics to the GRPC OTEL collector.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TELEMETRY_DISABLE_TRACING</code></td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to disable sending traces to the GRPC OTEL collector.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TELEMETRY_NAMESPACE</code></td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">If set then use this as value for the namespace label when sending telemetry</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TELEMETRY_PROVIDER</code></td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">otlp</td>
      <td scope="row" data-label="Notes">If set to "otlp" then telemetry is sent to the GRPC OTEL collector.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TOKIO_CONSOLE_ENABLED</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to enable [tokio console](https://github.com/tokio-rs/console).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TOKIO_CONSOLE_RETENTION</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">60</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How long, in seconds, to retain data for completed events.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TOKIO_CONSOLE_SOCKET_ADDR</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a socket address</td>
      <td scope="row" data-label="Notes">The socket address that Tokio Console will bind to.</td>
    </tr>
  </tbody>
</table>

### Vector search config

_(since v3.3.0)_

These variables tune pre-filtered vector search. When a KNN query on an HNSW or DiskANN index has `WHERE` conditions that other indexes can answer, SurrealDB first evaluates those conditions into an allow-list of matching records and restricts the vector search to it. See [How the filter is applied](/docs/learn/data-models/vector-search/similarity-search.md#how-the-filter-is-applied).

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KNN_PREFILTER_ENABLED</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether KNN queries build an allow-list from their <code>WHERE</code> conditions. When <code>false</code>, the conditions are checked for each candidate during the index traversal instead, as before 3.3.0.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KNN_PREFILTER_EXACT_THRESHOLD</code></td>
      <td scope="row" data-label="Default">2000</td>
      <td scope="row" data-label="Allowed values">A u64</td>
      <td scope="row" data-label="Notes">The allow-list size at or below which the search does not use the index graph at all, and instead scores every allowed record exactly. At this size an exact search is cheaper than a traversal and always finds the true nearest neighbours.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KNN_PREFILTER_EF_BOOST</code></td>
      <td scope="row" data-label="Default">4</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">The multiplier applied to the search width (<code>ef</code>) of a traversal restricted to an allow-list. A selective allow-list rejects most candidates, and a wider search recovers the recall that loses. The result is capped by <code>SURREAL_KNN_PREFILTER_EF_MAX</code> and is never lower than the <code>ef</code> the query asks for.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KNN_PREFILTER_EF_BOOST_THRESHOLD</code></td>
      <td scope="row" data-label="Default">100,000</td>
      <td scope="row" data-label="Allowed values">A u64</td>
      <td scope="row" data-label="Notes">The allow-list size above which the traversal stops multiplying <code>ef</code>, because a large allow-list rejects few candidates. Results are still restricted to the allow-list at every size.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KNN_PREFILTER_EF_MAX</code></td>
      <td scope="row" data-label="Default">1024</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">The ceiling for the multiplied <code>ef</code>. It never lowers the <code>ef</code> a query asks for.</td>
    </tr>
  </tbody>
</table>

The allow-list is built within the entry budget set by [`SURREAL_BITMAP_BRANCH_BUDGET`](#limits-config). When the budget is exceeded, the query falls back to checking the conditions during the traversal. A vector index created before 3.3.0 uses the allow-list only after it is rebuilt with [`REBUILD INDEX`](/docs/reference/query-language/statements/rebuild.md).

### WebSocket config

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_MAX_MESSAGE_SIZE</code></td>
      <td scope="row" data-label="Default">134,217,728 (128 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum WebSocket message size, which is also used as the maximum frame size. From 3.0.0 this replaces <code>SURREAL_WEBSOCKET_MAX_FRAME_SIZE</code>, which no longer exists and has no effect if set.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_MAX_WRITE_BUFFER_SIZE</code></td>
      <td scope="row" data-label="Default">Greatest possible usize value</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum write buffer size before backpressure is applied.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_READ_BUFFER_SIZE</code></td>
      <td scope="row" data-label="Default">131,072 (128 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The size of the read buffer for WebSocket connections. This controls how much data can be buffered when reading from WebSocket connections. Larger values can improve performance for high-throughput connections but consume more memory per connection.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_WRITE_BUFFER_SIZE</code></td>
      <td scope="row" data-label="Default">131,072 (128 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The size of the write buffer for WebSocket connections. This controls how much data can be buffered when writing to WebSocket connections. Larger values can improve performance for high-throughput connections but consume more memory per connection.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_RESPONSE_BUFFER_SIZE</code></td>
      <td scope="row" data-label="Default">0</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How many responses can be buffered when delivering to the client.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_RESPONSE_CHANNEL_SIZE</code></td>
      <td scope="row" data-label="Default">100</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Number of messages that can be queued for sending via WebSocket. From 3.3.0, replies and live query notifications have separate queues on each connection, each holding this many messages, and a value below 2 is raised to 2. A connection whose notification queue is full is closed, with a close frame giving the reason, rather than dropping notifications.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_RESPONSE_FLUSH_PERIOD</code></td>
      <td scope="row" data-label="Default">3</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How often (in milliseconds) any buffered responses are flushed to the WebSocket client.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_MAX_CONCURRENT_STREAMS</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">32</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum number of streaming queries (the <code>query_stream</code> RPC method) running at once on a single WebSocket connection. Each open stream holds an executing query, with its read snapshot or transaction, for as long as the client keeps reading. A request over the limit is refused with an error rather than queued.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEBSOCKET_STREAM_SEND_TIMEOUT</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">30</td>
      <td scope="row" data-label="Allowed values">Seconds (integer), clamped to 1-86,400</td>
      <td scope="row" data-label="Notes">How long a streaming query may wait to hand one frame to the connection before the stream is stopped. The wait resets for every frame, so it limits a stalled client rather than the length of a stream, and it applies even when <code>SURREAL_QUERY_TIMEOUT</code> is not set.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_TRANSACTIONS_PER_CONNECTION</code>_(since v3.2.2)_</td>
      <td scope="row" data-label="Default">64</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum concurrently open client-managed transactions (<code>begin</code> RPC) on a WebSocket connection's implicit default session. Further <code>begin</code> calls return <code>Too many open transactions</code> until a slot is freed by <code>commit</code>, <code>cancel</code>, <code>reset</code>, or disconnect. Does not apply to attached sessions (see <code>SURREAL_MAX_TRANSACTIONS_PER_SESSION</code>).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MAX_TRANSACTIONS_PER_SESSION</code>_(since v3.2.2)_</td>
      <td scope="row" data-label="Default">64</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Maximum concurrently open client-managed transactions within a single attached WebSocket session. Counted per session and independent of the connection default-session limit. Detaching or resetting a session cancels its open transactions and frees their slots.</td>
    </tr>
  </tbody>
</table>

### Operator and internal config

_(since v3.2.0)_

These settings are for operators, benchmarks, and advanced debugging - not typical application configuration. They are documented so core contributors and self-hosted deployments can find configuration options that already exist in the engine. Changing them can affect performance, reproducibility, or live-query behaviour; leave defaults in place unless you have a specific reason to tune them.

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_RAND_SEED</code></td>
      <td scope="row" data-label="Default">none (non-deterministic)</td>
      <td scope="row" data-label="Allowed values">A <code>u64</code></td>
      <td scope="row" data-label="Notes">Seeds the engine-wide RNG for reproducible runs in benchmarks and tests. Do not use in production.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LIVE_QUERY_ENGINE</code></td>
      <td scope="row" data-label="Default"><code>inline</code></td>
      <td scope="row" data-label="Allowed values"><code>inline</code>, <code>router</code></td>
      <td scope="row" data-label="Notes">Selects the live-query execution engine. <code>inline</code> is the historical behaviour; <code>router</code> decouples write cost from subscriber count (experimental rollout).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LIVE_QUERY_RETENTION</code></td>
      <td scope="row" data-label="Default">1h</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">How long the router engine retains live-query event history for subscriber resume. Only applies when <code>SURREAL_LIVE_QUERY_ENGINE=router</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HNSW_BUILD_SEED</code></td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A <code>u64</code></td>
      <td scope="row" data-label="Notes">Seeds HNSW index construction for reproducible graph layouts in benchmarks. Do not use in production.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRAPH_NUMERIC_IDS</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether background graph folds write numeric-encoded adjacency blocks, which store each entry's record id as a compact table-level document id. Existing blocks are converted on their next fold, and reads handle both encodings. Size the lookup cache with <code>SURREAL_GRAPH_RESOLVE_CACHE_SIZE</code>.</td>
    </tr>
  </tbody>
</table>

### Other environment variables

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '40%'}}>Environment variable</th>
      <th scope="col" style={{width: '20%'}}>Default</th>
      <th scope="col" style={{width: '20%'}}>Allowed values</th>
      <th scope="col" style={{width: '20%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_BUILD_METADATA</code></td>
      <td scope="row" data-label="Default">Automatically populated</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The version identifier of this build. Defaults to the CARGO_PKG_VERSION environment variable if not specified.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATASTORE_AOL</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">never</td>
      <td scope="row" data-label="Allowed values">never|sync|async</td>
      <td scope="row" data-label="Notes">Append-only log mode. Only used by the memory engine.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATASTORE_PERSIST</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a file path</td>
      <td scope="row" data-label="Notes">Filesystem path for persistence. Only used by the memory engine.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATASTORE_RETENTION</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">0 (unlimited)</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">Version retention period as a duration string. Used by the rocksdb and surrealkv engines. From 3.3.0 the memory engine refuses a non-zero value and the server does not start. _(since v3.3.0)_</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATASTORE_SNAPSHOT</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">never</td>
      <td scope="row" data-label="Allowed values">never|duration</td>
      <td scope="row" data-label="Notes">Snapshot interval. Only used by the memory engine.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATASTORE_SYNC_DATA</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">every</td>
      <td scope="row" data-label="Allowed values">never|every|duration</td>
      <td scope="row" data-label="Notes">The sync mode for the database. Used by memory, rocksdb, and surrealkv engines.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATASTORE_VERSIONED</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true|false|0|1</td>
      <td scope="row" data-label="Notes">Whether MVCC versioning is enabled, for use with the <a href="/docs/reference/query-language/statements/select.md#the-version-clause"><code>VERSION</code> clause</a>. Used by the rocksdb and surrealkv engines. From 3.3.0 the memory engine does not support versioned queries, and refuses <code>true</code> so that the server does not start. _(since v3.3.0)_</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_MEMORY_THRESHOLD</code></td>
      <td scope="row" data-label="Default">0 (disabled)</td>
      <td scope="row" data-label="Allowed values">A usize or suffixed integer</td>
      <td scope="row" data-label="Notes">The tracked memory, in bytes, above which queries are refused with <code>The query was not executed due to the memory threshold being reached</code>. The value can be specified as bytes (b, or without any suffix), kibibytes (k, kb, or kib), mebibytes (m, mb, or mib), or gibibytes (g, gb, or gib); Kubernetes-style <code>Gi</code> and <code>Mi</code> are not accepted. Unset or <code>0</code> disables the guard, and any other value is raised to at least 1 MiB. Tracked memory is the size the allocator reserves for each live heap allocation plus the RocksDB block cache, which is less than the process's resident memory, so set the threshold below the container's memory limit and above <code>SURREAL_ROCKSDB_BLOCK_CACHE_SIZE</code>: at or below the cache size, a full cache refuses every query until the server restarts. From 3.3.0 the reserved size rather than the requested size is counted, so a threshold carried over from an earlier release refuses queries at a lighter workload and may need raising. _(since v3.3.0)_ From 3.3.1 the threshold also stops a query that is already running: a query that reads records checks it after each batch, and fails with the same error once tracked memory is above it, rather than growing until the operating system stops the server. _(since v3.3.1)_</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_REGEX_CACHE_SIZE</code></td>
      <td scope="row" data-label="Default">1000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of computed regexes which can be cached in the engine.</td>
    </tr>
  </tbody>
</table>

## Command environment variables

Many of the arguments passed into [the CLI](/docs/reference/cli/db/commands/start.md) can be set using the above environment variables instead.

As each of these environment variables correspond to a flag or a required argument passed into a command, it is good practice to put together a command that matches the environment variables you wish to set. Once the database server conforms to your expected behaviour, you can then pull out the values passed into each flag for your environment variables.

For example, take the following command to start the database.

```bash
surreal db start --user root --pass secret --allow-net --deny-funcs "crypto::md5, http::post, http::delete"
```

If we now wanted to use environment variables instead of the `--allow-net` and `--deny-funcs` flags, we would use the `SURREAL_CAPS_ALLOW_NET` and `SURREAL_CAPS_DENY_FUNC` environment variables.

As the `--allow-net` flag was passed in without a following value, the same will be the case with the `SURREAL_CAPS_ALLOW_NET` environment variable, becoming `SURREAL_CAPS_ALLOW_NET=`. The `--deny-funcs` flag can also be used on its own to deny execution of all functions, but in this case is followed by a string to indicate which exact functions are not allowed to be executed. As such, the `SURREAL_CAPS_DENY_FUNC` environment variable must also be followed by a string, becoming `SURREAL_CAPS_DENY_FUNC="crypto::md5, http::post, http::delete"`.

The command would then look like the following:

**Bash**

```bash
SURREAL_CAPS_ALLOW_NET
SURREAL_CAPS_DENY_FUNC="crypto::md5, http::post, http::delete"
surreal db start --user root --pass secret
```

**PowerShell**

```powershell
$env:SURREAL_CAPS_ALLOW_NET
$env:SURREAL_CAPS_DENY_FUNC="crypto::md5, http::post, http::delete"
surreal db start --user root --pass secret
```

A command environment variable that takes a boolean will be set to true if the flag is present, and following it with `true` will cause an error.

For example, the `SURREAL_CAPS_ALLOW_ALL` environment variable is used to set whether to allow all capabilities such as scripting and allowing network access. The flag `--allow-all` is all that is needed to set to `true`. But as an environment variable, the value `true` must be included to override its default `false` value.

**Bash**

```bash title="SURREAL_CAPS_ALLOW_ALL example"
# set to default false
surreal db start

# Same, but implicitly shown
SURREAL_CAPS_ALLOW_ALL=false surreal db start

# Set to true
SURREAL_CAPS_ALLOW_ALL=true surreal db start

# Set to true
surreal db start --allow-all

# Error: only --allow-all needed to set to true
surreal db start --allow-all true
```

**PowerShell**

```powershell title="SURREAL_CAPS_ALLOW_ALL example"
# set to default false
surreal db start

# Same, but implicitly shown
$env:SURREAL_CAPS_ALLOW_ALL = "false"
surreal db start

# Set to true
$env:SURREAL_CAPS_ALLOW_ALL = "true"
surreal db start

# Set to true
surreal db start --allow-all

# Error: only --allow-all needed to set to true
surreal db start --allow-all true
```

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '25%'}}>Environment variable</th>
      <th scope="col" style={{width: '15%'}}>Command arg</th>
      <th scope="col" style={{width: '12%'}}>For command(s)</th>
      <th scope="col" style={{width: '12%'}}>Default</th>
      <th scope="col" style={{width: '18%'}}>Allowed values</th>
      <th scope="col" style={{width: '18%'}}>Details</th>
    </tr>
  </thead>
  <tbody>
  <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ASYNC_EVENT_PROCESSING_INTERVAL</code>_(since v3.0.0)_ </td>
      <td scope="row" data-label="Command arg"><code>async-event-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">5s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The interval at which to process async events.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_AUTH_LEVEL</code></td>
      <td scope="row" data-label="Command arg"><code>auth-level</code></td>
      <td scope="row" data-label="Command">`export`, `import`, `sql`</td>
      <td scope="row" data-label="Default">root</td>
      <td scope="row" data-label="Allowed values">root, namespace, ns, database, db</td>
      <td scope="row" data-label="Notes">Authentication level to use when connecting.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_BIND</code></td>
      <td scope="row" data-label="Command arg"><code>bind</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">127.0.0.1:8000</td>
      <td scope="row" data-label="Allowed values">String to an address</td>
      <td scope="row" data-label="Notes">The hostname or IP address(es) to listen for connections on.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_POSTGRES_BIND</code></td>
      <td scope="row" data-label="Command arg"><code>postgres-bind</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">(disabled)</td>
      <td scope="row" data-label="Allowed values">String to an address</td>
      <td scope="row" data-label="Notes">The hostname or IP address to listen for <a href="/docs/reference/rest-api/postgres-protocol.md">Postgres wire protocol</a> connections on.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_ALL</code></td>
      <td scope="row" data-label="Command arg"><code>allow-all</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Allow all capabilities.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_ARBITRARY_QUERY</code></td>
      <td scope="row" data-label="Command arg"><code>allow-arbitrary-query</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">guest, record, system (comma-separated)</td>
      <td scope="row" data-label="Notes">Allows arbitrary queries to be used by user groups except when specifically denied. Alternatively, you can provide a comma-separated list of user groups to allow specifically denied user groups to prevail over any other allowed user group.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_EVAL_QUERY</code>_(since v3.2.0)_</td>
      <td scope="row" data-label="Command arg"><code>allow-eval-query</code></td>
      <td scope="row" data-label="Command">`start`, `sql`</td>
      <td scope="row" data-label="Default">none (denied for all subjects)</td>
      <td scope="row" data-label="Allowed values">guest, record, system (comma-separated)</td>
      <td scope="row" data-label="Notes">Allow <code>eval::surql</code> and <code>eval::gql</code> for listed subject groups. Not enabled by <code>--allow-all</code>. Still subject to <a href="/docs/learn/security/authorization/capabilities.md#arbitrary-queries">arbitrary-query</a> restrictions - <code>--deny-arbitrary-query</code> blocks <code>eval</code> for that subject even when eval is allowed here. For remote clients, set on the <code>start</code> process only. See <a href="/docs/reference/cli/db/commands/sql.md#capabilities-and-remote-connections">Capabilities and remote connections</a>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_EXPERIMENTAL</code></td>
      <td scope="row" data-label="Command arg"><code>allow-experimental</code></td>
      <td scope="row" data-label="Command">`start`, `sql`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">files, surrealism (comma-separated; legacy <code>gql</code> accepted but unused from 3.3.0)</td>
      <td scope="row" data-label="Notes">Allow execution of experimental features. For remote clients, set on the <code>start</code> process. On <code>surreal db sql</code>, affects embedded engines and REPL parse validation only. See <a href="/docs/reference/cli/db/commands/start.md#experimental-capabilities">experimental capabilities</a>. From 3.3.0, ISO GQL (Cypher Query Language) is on by default and does not need this variable.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_FUNC</code></td>
      <td scope="row" data-label="Command arg"><code>allow-funcs</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">all functions allowed</td>
      <td scope="row" data-label="Allowed values">Empty, <code>*</code>, or comma-separated function paths</td>
      <td scope="row" data-label="Notes">Allow execution of all functions except for functions that are specifically denied. Set to an empty value or <code>*</code> to allow all functions. Use a comma-separated list (for example, <code>array,string::len,http::get</code>) to allow specific function families or names. Values such as <code>true</code> are not valid. The environment variable name is singular (<code>FUNC</code>), matching the <code>--allow-funcs</code> flag.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_GUESTS</code></td>
      <td scope="row" data-label="Command arg"><code>allow-guests</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Allow guest users to execute queries.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_NET</code></td>
      <td scope="row" data-label="Command arg"><code>allow-net</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">Comma-separated list of paths</td>
      <td scope="row" data-label="Notes">Allow all or certain outbound network access.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_SCRIPT</code></td>
      <td scope="row" data-label="Command arg"><code>allow-scripting</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Allow execution of embedded scripting functions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_ALLOW_INSECURE_STORABLE_CLOSURES</code>_(since v2.5.0)_</td>
      <td scope="row" data-label="Command arg"><code>allow-insecure-storable-closures</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Takes a boolean. From 2.5.0, closures cannot be stored, which removes a potential attack surface; on 2.5.x and 2.6.x this capability allows them again. Removed in 3.0.0, where closures can never be stored and the flag is rejected.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_DENY_ALL</code></td>
      <td scope="row" data-label="Command arg"><code>deny-all</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Deny all capabilities.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_DENY_EVAL_QUERY</code>_(since v3.2.0)_</td>
      <td scope="row" data-label="Command arg"><code>deny-eval-query</code></td>
      <td scope="row" data-label="Command">`start`, `sql`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">guest, record, system (comma-separated)</td>
      <td scope="row" data-label="Notes">Deny <code>eval::surql</code> and <code>eval::gql</code> for listed subject groups. Deny prevails over allow at the same specificity. For remote clients, set on the <code>start</code> process.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_DENY_FUNC</code></td>
      <td scope="row" data-label="Command arg"><code>deny-funcs</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false, comma-separated list</td>
      <td scope="row" data-label="Notes">Deny execution of all or certain functions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_DENY_GUESTS</code></td>
      <td scope="row" data-label="Command arg"><code>deny-guests</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Deny guest users from executing queries.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_DENY_NET</code></td>
      <td scope="row" data-label="Command arg"><code>deny-net</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false, comma-separated list</td>
      <td scope="row" data-label="Notes">Deny all or certain outbound access paths.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CAPS_DENY_SCRIPT</code></td>
      <td scope="row" data-label="Command arg"><code>deny-scripting</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Deny execution of embedded scripting functions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CHANGEFEED_GC_INTERVAL</code></td>
      <td scope="row" data-label="Command arg"><code>changefeed-gc-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">30s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The interval at which to perform changefeed garbage collection.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_CLIENT_IP</code></td>
      <td scope="row" data-label="Command arg"><code>client-ip</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">none, socket, CF-Connecting-IP, Fly-Client-IP, True-Client-IP, X-Real-IP, X-Forwarded-For, Forwarded</td>
      <td scope="row" data-label="Notes">The method of detecting the client's IP address. _(since v3.1.0)_ <code>Forwarded</code> parses the RFC 7239 <code>Forwarded</code> header (<code>for=</code> parameter).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATABASE</code></td>
      <td scope="row" data-label="Command arg"><code>database</code></td>
      <td scope="row" data-label="Command">`sql`</td>
      <td scope="row" data-label="Default">main</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The database selected when starting the REPL.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DATABASE</code></td>
      <td scope="row" data-label="Command arg"><code>database</code></td>
      <td scope="row" data-label="Command">`export`, `import`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The database selected for the import or export.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DEFAULT_DATABASE</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>default-database</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">main</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The default database to use when starting a SurrealDB instance.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DEFAULT_NAMESPACE</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>default-namespace</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">main</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The default namespace to use when starting a SurrealDB instance.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DURABLE_SESSIONS</code>_(since v3.2.2)_</td>
      <td scope="row" data-label="Command arg"><code>durable-sessions</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Persist client-attached HTTP RPC sessions in the datastore so they survive restarts and can be resumed on any node sharing the storage. Off by default. WebSocket sessions are not durable. The persisted copy includes authentication state and is stored unencrypted. See <a href="/docs/reference/cli/db/commands/start.md#durable-http-rpc-sessions">Durable HTTP RPC sessions</a>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DURABLE_SESSION_GC_INTERVAL</code>_(since v3.2.2)_</td>
      <td scope="row" data-label="Command arg"><code>durable-session-gc-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">60s</td>
      <td scope="row" data-label="Allowed values">A duration; <code>0</code> disables the background sweep</td>
      <td scope="row" data-label="Notes">How often expired durable HTTP RPC sessions are purged. Lazy expiry on load still applies when the sweep is disabled. Only meaningful when durable sessions are enabled.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_DURABLE_SESSION_TTL</code>_(since v3.2.2)_</td>
      <td scope="row" data-label="Command arg"><code>durable-session-ttl</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">24h</td>
      <td scope="row" data-label="Allowed values">A duration greater than zero</td>
      <td scope="row" data-label="Notes">Idle lifetime of a persisted HTTP RPC session; each use refreshes the expiry (sliding TTL). Must be greater than zero when durable sessions are enabled.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_GRAPH_FOLD_INTERVAL</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Command arg"><code>graph-fold-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">5s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The interval between background passes that fold a vertex's per-edge graph adjacency keys into packed blocks. A pass also starts early when a write queues fold work or a traversal meets a vertex with many unfolded keys. See also <code>SURREAL_GRAPH_FOLD_BATCH</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HIDE_WELCOME</code></td>
      <td scope="row" data-label="Command arg"><code>hide-welcome</code></td>
      <td scope="row" data-label="Command">`sql`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to show the welcome message when starting the REPL.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_IMPORT_FILE</code></td>
      <td scope="row" data-label="Command arg"><code>import-file</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A file path</td>
      <td scope="row" data-label="Notes">Path to a SurrealQL file that will be imported when starting the server.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_INDEX_COMPACTION_INTERVAL</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>index-compaction-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">5s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The interval at which to compact queued index updates. Writes to a full-text, count, or vector index enqueue pending updates that a background task folds into the index; this controls how often that task runs. One node in a cluster performs the work for the whole cluster. Lengthening the interval allows the pending backlog to grow, which increases the work each subsequent query must do to read through it.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KEY</code></td>
      <td scope="row" data-label="Command arg"><code>key</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string 16, 24, or 32 bytes long</td>
      <td scope="row" data-label="Notes">Encryption key to use for on-disk encryption. Not currently in use.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KVS_CA</code></td>
      <td scope="row" data-label="Command arg"><code>kvs-ca</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a path</td>
      <td scope="row" data-label="Notes">Path to the CA file used when connecting to the remote KV store.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KVS_CRT</code></td>
      <td scope="row" data-label="Command arg"><code>kvs-crt</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a path</td>
      <td scope="row" data-label="Notes">Path to the certificate file used when connecting to the remote KV store.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_KVS_KEY</code></td>
      <td scope="row" data-label="Command arg"><code>kvs-key</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a path</td>
      <td scope="row" data-label="Notes">Path to the private key file used when connecting to the remote KV store.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LAZY_SURREALISM</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Command arg"><code>lazy-surrealism</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to lazy-load Surrealism modules instead of eagerly compiling them at server startup.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG</code></td>
      <td scope="row" data-label="Command arg"><code>log</code></td>
      <td scope="row" data-label="Command">`start`, `fix`</td>
      <td scope="row" data-label="Default">info</td>
      <td scope="row" data-label="Allowed values">none, full, error, warn, info, debug, trace</td>
      <td scope="row" data-label="Notes">The logging level for the database server.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_FILE_ENABLED</code>_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-file-enabled</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Toggles file output.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_FILE_FORMAT</code>_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-file-format</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">text, json</td>
      <td scope="row" data-label="Notes">The format for log file output.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_FILE_LEVEL</code>_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-file-level</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">none, full, error, warn, info, debug, trace</td>
      <td scope="row" data-label="Notes">Override the logging level for file output</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_FILE_NAME</code>_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-file-name</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">surrealdb.log</td>
      <td scope="row" data-label="Allowed values">String to a file</td>
      <td scope="row" data-label="Notes">Filename for logs (default: `surrealdb.log`)</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_FILE_PATH</code>_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-file-path</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">logs</td>
      <td scope="row" data-label="Allowed values">String to a path</td>
      <td scope="row" data-label="Notes">Sets the directory for logs</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_FILE_ROTATION</code>_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-file-rotation</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">daily</td>
      <td scope="row" data-label="Allowed values">daily, hourly, never</td>
      <td scope="row" data-label="Notes">Sets the rotation duration for logs.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_FORMAT</code>_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-format</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">text</td>
      <td scope="row" data-label="Allowed values">text, json</td>
      <td scope="row" data-label="Notes">Sets the format for logs.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_OTEL_LEVEL</code><br />_(since v2.4.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-otel-level</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">SURREAL_LOG logging level</td>
      <td scope="row" data-label="Allowed values">none, full, error, warn, info, debug, trace</td>
      <td scope="row" data-label="Notes">Override the logging level for OpenTelemetry</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_SOCKET</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-socket</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a host:port</td>
      <td scope="row" data-label="Notes">Send logs to the specified host:port</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_SOCKET_FORMAT</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-socket-format</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">text</td>
      <td scope="row" data-label="Allowed values">text, json</td>
      <td scope="row" data-label="Notes">  Set the format of the logs to the socket.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_LOG_SOCKET_LEVEL</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>log-socket-level</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">SURREAL_LOG logging level</td>
      <td scope="row" data-label="Allowed values">none, full, error, warn, info, debug, trace</td>
      <td scope="row" data-label="Notes">  Override the logging level for socket logs. Possible values: none, full, error, warn, info, debug, trace</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NAME</code></td>
      <td scope="row" data-label="Command arg"><code>name</code></td>
      <td scope="row" data-label="Command">`ml export`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The name of the model.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NAMESPACE</code></td>
      <td scope="row" data-label="Command arg"><code>namespace</code></td>
      <td scope="row" data-label="Command">`sql`</td>
      <td scope="row" data-label="Default">main</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The namespace to connect to via the REPL.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NAMESPACE</code></td>
      <td scope="row" data-label="Command arg"><code>namespace</code></td>
      <td scope="row" data-label="Command">`export`, `import`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The namespace selected for the import/export operation.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NO_BANNER</code></td>
      <td scope="row" data-label="Command arg"><code>no-banner</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to hide the startup banner.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NO_DEFAULTS</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>no-defaults</code></td>
      <td scope="row" data-label="Command"><code>`start`</code></td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to disable default namespace and database creation. Conflicts with SURREAL_DEFAULT_DATABASE and SURREAL_DEFAULT_NAMESPACE, which set a default value for namespace and database for a new instance.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NO_IDENTIFICATION_HEADERS</code></td>
      <td scope="row" data-label="Command arg"><code>no-identification-headers</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to suppress the server name and version headers.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NODE_MEMBERSHIP_CHECK_INTERVAL</code></td>
      <td scope="row" data-label="Command arg"><code>node-membership-check-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">15s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The interval at which to process and archive inactive nodes.</td>
    </tr>
  <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NODE_MEMBERSHIP_CLEANUP_INTERVAL</code></td>
      <td scope="row" data-label="Command arg"><code>node-membership-cleanup-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">300s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The interval at which to process and cleanup archived nodes.</td>
    </tr>
  <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_NODE_MEMBERSHIP_REFRESH_INTERVAL</code></td>
      <td scope="row" data-label="Command arg"><code>node-membership-refresh-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">3s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The interval at which to refresh node registration information. The <a href="/docs/reference/rest-api/http-protocol.md#ready"><code>/ready</code></a> endpoint reports the node unhealthy when its cluster heartbeat is older than three times this interval (9s by default). The multiple is fixed and cannot be configured.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_PASS</code></td>
      <td scope="row" data-label="Command arg"><code>pass</code></td>
      <td scope="row" data-label="Command">`export`, `import`, `sql`, `start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">Database authentication password to use when connecting.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var">SURREAL_PATH</td>
      <td scope="row" data-label="Command arg"><code>path</code></td>
      <td scope="row" data-label="Command">`fix`, `start`</td>
      <td scope="row" data-label="Default">memory</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">Database path used for storing data. As a required argument (albeit with a default), it is not passed in via `--path`.</td>
    </tr>
<tr>
      <td scope="row" data-label="Env var"><code>SURREAL_PLANNER_STRATEGY</code>_(since v3.0.0)_</td>
      <td scope="row" data-label="Command arg"><code>planner-strategy</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">best-effort</td>
      <td scope="row" data-label="Allowed values">best-effort|compute-only|all-read-only</td>
      <td scope="row" data-label="Notes">Which strategy to use with the new query planner introduced in SurrealDB 3.0. The default setting uses the new planner for read-only statements, falling back to the previous compute planner on unimplemented paths. The new planner can be skipped entirely by using compute-only.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_QUERY_TIMEOUT</code></td>
      <td scope="row" data-label="Command arg"><code>query-timeout</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The maximum duration that a batch of statements can run for. From 3.3.0 it is also a hard wall-clock limit on each HTTP <code>/sql</code>, <code>/gql</code> and <code>/graphql</code> request and on each RPC method call. An HTTP <code>/sql</code> or <code>/gql</code> request that exceeds it is answered with <code>504 Gateway Timeout</code>, and a <code>/graphql</code> request with a GraphQL error. The <code>begin</code>, <code>commit</code> and <code>cancel</code> RPC methods are exempt, but the calls made inside the transaction they control are still limited individually. _(since v3.3.0)_</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_RECLAIM_INTERVAL</code>_(since v3.2.0)_</td>
      <td scope="row" data-label="Command arg"><code>reclaim-interval</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">60s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">How often the background reaper scans for tombstoned namespace, database, and index data to physically delete after a <code>REMOVE</code> statement. On the 2.x line it is available from 2.7.0 and covers namespaces and databases only.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_RECLAIM_GRACE</code>_(since v3.2.0)_</td>
      <td scope="row" data-label="Command arg"><code>reclaim-grace</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">10m</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">Minimum age a removed namespace, database, or index must reach before its data is reclaimed. The effective grace is the maximum of this value and <code>--tikv-gc-lifetime</code> on TiKV backends. Not available on 2.x.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SLOW_QUERY_LOG_THRESHOLD</code><br />_(since v2.3.8)_</td>
      <td scope="row" data-label="Command arg"><code>slow-log-threshold</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">A duration specifying the minimum execution time after which a log is made to indicate a slow query</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SLOW_QUERY_LOG_PARAM_ALLOW</code><br /><code>slow-log-param-allow</code> _(since v2.3.9)_</td>
      <td scope="row" data-label="Command arg"><code>slow-log-param-allow</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">Comma-separated strings</td>
      <td scope="row" data-label="Notes">A comma-separated list of parameter names to include in slow query logs.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SLOW_QUERY_LOG_PARAM_DENY</code>_(since v2.3.9)_</td>
      <td scope="row" data-label="Command arg"><code>slow-log-param-deny</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">Comma-separated strings</td>
      <td scope="row" data-label="Notes">A comma-separated list of parameter names to omit from slow query logs.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_STRICT</code></td>
      <td scope="row" data-label="Command arg"><code>strict</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether strict mode is enabled on this database instance. Ignored since SurrealDB 3.0 after which strictness is defined [per database](/docs/reference/query-language/statements/define/database.md#defining-a-strict-database) instead of instance.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_STARTUP_OPERATION_TIMEOUT</code></td>
      <td scope="row" data-label="Command arg"><code>startup-operation-timeout</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">60s</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">How long each built-in startup datastore operation may keep retrying before the server gives up. It is a per-operation budget rather than a total for startup, and it covers initialising the default namespace and database, initialising the root credentials, and registering this node in the cluster. Raise it where the storage backend is slow to accept the first writes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TEMPORARY_DIRECTORY</code></td>
      <td scope="row" data-label="Command arg"><code>temporary-directory</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a directory</td>
      <td scope="row" data-label="Notes">Sets the directory for storing temporary database files</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TOKEN</code></td>
      <td scope="row" data-label="Command arg"><code>token</code></td>
      <td scope="row" data-label="Command">`export`, `import`, `sql`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">Authentication token in JWT format to use when connecting.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TRANSACTION_TIMEOUT</code></td>
      <td scope="row" data-label="Command arg"><code>transaction-timeout</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The maximum duration that any single transaction can run for.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_UNAUTHENTICATED</code></td>
      <td scope="row" data-label="Command arg"><code>unauthenticated</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to allow unauthenticated access.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_USER</code></td>
      <td scope="row" data-label="Command arg"><code>user</code></td>
      <td scope="row" data-label="Command">`export`, `import`, `sql`, start</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">Database authentication username to use when connecting.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_VERSION</code></td>
      <td scope="row" data-label="Command arg"><code>version</code></td>
      <td scope="row" data-label="Command">`ml export`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">The version of the ML model.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEB_CRT</code></td>
      <td scope="row" data-label="Command arg"><code>web-crt</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a path</td>
      <td scope="row" data-label="Notes">Path to the certificate file for encrypted client connections.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_WEB_KEY</code></td>
      <td scope="row" data-label="Command arg"><code>web-key</code></td>
      <td scope="row" data-label="Command">`start`</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">String to a path</td>
      <td scope="row" data-label="Notes">Path to the private key file for encrypted client connections.</td>
    </tr>
  </tbody>
</table>

### Authentication rate limiting environment variables

_(since v3.3.0)_

These variables throttle authentication attempts on the HTTP `/signin` and `/signup` endpoints, per client address. Both endpoints draw on one shared budget. The limiter is off by default, and setting any of the burst, rate, or tracked-client values to `0` also turns it off.

An attempt that exceeds the budget is answered with `429 Too Many Requests` and a `Retry-After` header giving the seconds to wait.

> [!IMPORTANT]
> The limiter keys on the address resolved by [`--client-ip`](/docs/reference/cli/db/commands/start.md), so it needs a strategy that yields one address per client. With `--client-ip socket` behind a proxy, every request resolves to the proxy's address and shares a single budget, which throttles all authentication collectively. With `--client-ip none` no address is available and the limiter does nothing. A header strategy is only as trustworthy as the proxy setting the header: a request arriving without it yields no address and is admitted unchecked, so a header strategy protects only a deployment where every request to these endpoints passes through that proxy.

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '50%'}}>Environment variable</th>
      <th scope="col" style={{width: '15%'}}>Default</th>
      <th scope="col" style={{width: '15%'}}>Allowed values</th>
      <th scope="col" style={{width: '30%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_AUTH_RATE_LIMIT_ENABLED</code></td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to rate limit authentication attempts on the HTTP <code>/signin</code> and <code>/signup</code> endpoints per client address. Only <code>true</code> and <code>false</code> are accepted; any other value is ignored and the default applies.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_AUTH_RATE_LIMIT_BURST</code></td>
      <td scope="row" data-label="Default">60</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">How many authentication attempts a single client address may make before being throttled. Set to <code>0</code> to disable the limiter.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_AUTH_RATE_LIMIT_PER_MINUTE</code></td>
      <td scope="row" data-label="Default">60</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">The sustained rate, in attempts per minute, at which a client address's budget refills. The default of 60 is one attempt per second. Set to <code>0</code> to disable the limiter.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_HTTP_AUTH_RATE_LIMIT_MAX_TRACKED_CLIENTS</code></td>
      <td scope="row" data-label="Default">16384</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">How many client addresses the limiter tracks at once. Unauthenticated callers write to this store, so it is a bounded cache: at capacity a new address evicts an existing entry rather than the store growing or the limiter switching off. An evicted address starts again from a full burst, so the sustained rate binds an address only while it stays tracked. Size this above the number of distinct addresses the instance authenticates. Set to <code>0</code> to disable the limiter.</td>
    </tr>
  </tbody>
</table>

## Storage backend environment variables

These environment variables are used to configure the storage backend for SurrealDB.

### RocksDB environment variables

Many RocksDB environment variables pertain to memory use. The default configuration results in the following rough estimates of RocksDB memory use on different instances:

| Instance memory size  | Estimate
| ------------- |:-------------:|
| 512 MiB | ~ 80MiB |
| 1 GiB | ~ 80MiB
| 2 GiB | ~ 640MiB
| 4 GiB | ~ 1.25GiB
| 8 GiB | ~ 3.25GiB
| 24 GiB | ~ 12GiB
| 128 GiB | ~ 67GiB

The available environment variables for configuring a RocksDB instance are:

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '50%'}}>Environment variable</th>
      <th scope="col" style={{width: '15%'}}>Default</th>
      <th scope="col" style={{width: '15%'}}>Allowed values</th>
      <th scope="col" style={{width: '30%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BACKGROUND_FLUSH</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">false, true</td>
      <td scope="row" data-label="Notes">Whether to enable background WAL file flushing. 2.x only: from 3.0.0, set a duration on <code>SURREAL_DATASTORE_SYNC_DATA</code> instead.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BACKGROUND_FLUSH_INTERVAL</code></td>
      <td scope="row" data-label="Default">200 (milliseconds)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The interval in milliseconds between background flushes. 2.x only: from 3.0.0, set a duration on <code>SURREAL_DATASTORE_SYNC_DATA</code> instead.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BLOB_COMPACTION_READAHEAD_SIZE</code></td>
      <td scope="row" data-label="Default">0</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Readahead size for blob compaction/GC.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BLOB_COMPRESSION_TYPE</code></td>
      <td scope="row" data-label="Default">snappy</td>
      <td scope="row" data-label="Allowed values">none, snappy, lz4, zstd</td>
      <td scope="row" data-label="Notes">Compression type used for blob files.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BLOB_FILE_SIZE</code></td>
      <td scope="row" data-label="Default">268,435,456 (256 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The target blob file size for RocksDB.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BLOB_GC_AGE_CUTOFF</code></td>
      <td scope="row" data-label="Default">0.5</td>
      <td scope="row" data-label="Allowed values">Float between 0 and 1</td>
      <td scope="row" data-label="Notes">Fractional age cutoff for blob GC.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BLOB_GC_FORCE_THRESHOLD</code></td>
      <td scope="row" data-label="Default">0.5</td>
      <td scope="row" data-label="Allowed values">Float between 0 and 1</td>
      <td scope="row" data-label="Notes">Discardable ratio threshold to force GC.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BLOCK_CACHE_SIZE</code></td>
      <td scope="row" data-label="Default">Dynamically calculated via greater of ((system memory / 2) - 1 GiB) and 16MiB</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">RocksDB <a href="https://github.com/facebook/rocksdb/wiki/memory-usage-in-rocksdb">block cache size</a> in bytes</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_BLOCK_SIZE</code></td>
      <td scope="row" data-label="Default">65,536 (64 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The size of each uncompressed data block in bytes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_COMPACTION_READAHEAD_SIZE</code></td>
      <td scope="row" data-label="Default">4 MiB (systems under 4 GiB), 8 MiB (up to 16 GiB), 16 MiB (others)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The readahead buffer size used during compaction.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_COMPACTION_STYLE</code> </td>
      <td scope="row" data-label="Default">level</td>
      <td scope="row" data-label="Allowed values">level, universal</td>
      <td scope="row" data-label="Notes">Use to specify the database compaction style.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_COMPACT_ON_SHUTDOWN</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether a graceful shutdown runs a full compaction of the database after flushing the memtables, as <code>ALTER SYSTEM COMPACT</code> does. On a large database this can take minutes or hours, which can be longer than the shutdown grace period of a container orchestrator.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_DELETION_FACTORY_DELETE_COUNT</code></td>
      <td scope="row" data-label="Default">50</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of deletions to track in the window.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_DELETION_FACTORY_RATIO</code></td>
      <td scope="row" data-label="Default">0.5</td>
      <td scope="row" data-label="Allowed values">A float</td>
      <td scope="row" data-label="Notes">The ratio of deletions to track in the window.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_DELETION_FACTORY_WINDOW_SIZE</code></td>
      <td scope="row" data-label="Default">1000</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The size of the window used to track deletions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_ENABLE_BLOB_FILES</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to enable separate key and value file storage.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_ENABLE_BLOB_GC</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to enable blob garbage collection for RocksDB.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_ENABLE_PIPELINED_WRITES</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to use separate queues for WAL writes and memtable writes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_FILE_COMPACTION_TRIGGER</code></td>
      <td scope="row" data-label="Default">4</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of files needed to trigger level 0 compaction.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_FILE_READS_FOR_AUTO_READAHEAD</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">2</td>
      <td scope="row" data-label="Allowed values">A u64</td>
      <td scope="row" data-label="Notes">The number of sequential reads an iterator makes on one SST file before RocksDB starts to prefetch. Set to <code>0</code> to prefetch from the first read.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_GROUPED_COMMIT_MAX_BATCH_SIZE</code></td>
      <td scope="row" data-label="Default">4096</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of transactions in a single grouped commit batch. Used to prevent unbounded memory growth while still allowing large batches for efficiency. Larger batches improve throughput but increase memory usage and commit latency.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_GROUPED_COMMIT_TIMEOUT</code></td>
      <td scope="row" data-label="Default">5ms</td>
      <td scope="row" data-label="Allowed values">A duration</td>
      <td scope="row" data-label="Notes">The maximum wait time in nanosecond before forcing a grouped commit. Used to ensure that transactions do not wait indefinitely when concurrency is low, and to balance between transaction latency and write throughput.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_GROUPED_COMMIT_WAIT_THRESHOLD</code></td>
      <td scope="row" data-label="Default">12</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Threshold for deciding whether to wait for more transactions. If the current batch size is greater or equal to this threshold (and below ROCKSDB_GROUPED_COMMIT_MAX_BATCH_SIZE), then the coordinator will wait up to ROCKSDB_GROUPED_COMMIT_TIMEOUT to collect more transactions. Smaller batches are flushed immediately to preserve low latency.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_INITIAL_AUTO_READAHEAD_SIZE</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">8,192 (8 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The size of the first prefetch. Each following read doubles it, up to <code>SURREAL_ROCKSDB_MAX_AUTO_READAHEAD_SIZE</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_JOBS_COUNT</code></td>
      <td scope="row" data-label="Default">Number of CPUs * 2</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of threads to use for flushing and compaction.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_KEEP_LOG_FILE_NUM</code></td>
      <td scope="row" data-label="Default">10</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of information log files to keep.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_LEVEL0_SLOWDOWN_WRITES_TRIGGER</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">8</td>
      <td scope="row" data-label="Allowed values">An i32</td>
      <td scope="row" data-label="Notes">The number of level-0 files at which RocksDB starts to slow down writes. The RocksDB default is 20.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_LEVEL0_STOP_WRITES_TRIGGER</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">12</td>
      <td scope="row" data-label="Allowed values">An i32</td>
      <td scope="row" data-label="Notes">The number of level-0 files at which RocksDB stops writes until compaction reduces the count. Keep it above <code>SURREAL_ROCKSDB_LEVEL0_SLOWDOWN_WRITES_TRIGGER</code>. The RocksDB default is 36.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_MAX_AUTO_READAHEAD_SIZE</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">262,144 (256 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The largest prefetch an iterator grows to. A larger value can make long range scans faster, but uses more memory for each iterator, so many concurrent scans multiply the cost.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_MAX_CONCURRENT_SUBCOMPACTIONS</code></td>
      <td scope="row" data-label="Default">4</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number threads which will perform compactions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_MAX_OPEN_FILES</code></td>
      <td scope="row" data-label="Default">1024</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of open files which can be opened by RocksDB.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_MAX_WRITE_BUFFER_NUMBER</code></td>
      <td scope="row" data-label="Default">2 (systems under 4 GiB), 4 (up to 16 GiB), 8 (up to 64 GiB), 32 (others)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of write buffers which can be used.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_MEMTABLE_PREFIX_BLOOM_RATIO</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">0.1</td>
      <td scope="row" data-label="Allowed values">An f64</td>
      <td scope="row" data-label="Notes">The size of the prefix bloom filter in each memtable, as a ratio of the write buffer size. RocksDB caps it at 0.25. Set to <code>0</code> to disable it. Only used when <code>SURREAL_ROCKSDB_PREFIX_EXTRACTOR_ENABLED</code> is true.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_MIN_BLOB_SIZE</code></td>
      <td scope="row" data-label="Default">4096</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The minimum size in bytes of a value for it to be stored in blob files.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_MIN_WRITE_BUFFER_NUMBER_TO_MERGE</code></td>
      <td scope="row" data-label="Default">2</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The minimum number of write buffers to merge before writing to disk.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_PERIODIC_COMPACTION_SECONDS</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">3600</td>
      <td scope="row" data-label="Allowed values">A u64</td>
      <td scope="row" data-label="Notes">The interval in seconds after which RocksDB rewrites an SST file that no other compaction has touched. This removes old versions and tombstones from data that is rarely written. Set to <code>0</code> to disable.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_PREFIX_EXTRACTOR_ENABLED</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether SST bloom filters are built on table and key-type prefixes, so that a scan can skip SST files that hold nothing from the table it reads.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_RUNTIME_RESERVE</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">2</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of runtime worker threads kept free for asynchronous work while other transactions wait on a storage call. A larger value keeps more threads free under load, but lowers the number of storage calls that can run at once. See <code>SURREAL_RUNTIME_WORKER_THREADS</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_SCAN_VERIFY_CHECKSUMS</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether scans and counts verify the checksum of each block when it is first read from disk. Disabling it makes cold scans faster, and is only safe on trusted storage.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_SHUTDOWN_WAIT_FOR_COMPACT_SECONDS</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">30</td>
      <td scope="row" data-label="Allowed values">A u64</td>
      <td scope="row" data-label="Notes">How long a graceful shutdown waits in seconds for a compaction that started after the final flush, so that the next start does not have to repeat it. Set to <code>0</code> to wait without a limit.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_SST_MAX_ALLOWED_SPACE_USAGE</code></td>
      <td scope="row" data-label="Default">0</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum allowed space usage for SST files in bytes. The default of 0 means unlimited and disables space monitoring. When this limit is reached, the datastore enters read-and-deletion-only mode, where only read and delete operations are allowed. This allows gradual space recovery through data deletion.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_STORAGE_LOG_LEVEL</code></td>
      <td scope="row" data-label="Default">warn</td>
      <td scope="row" data-label="Allowed values">none, full, error, warn, info, debug, trace</td>
      <td scope="row" data-label="Notes">The information log level of the RocksDB library.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_TARGET_FILE_SIZE_BASE</code></td>
      <td scope="row" data-label="Default">67,108,864 (64 MiB)</td>
      <td scope="row" data-label="Allowed values">-</td>
      <td scope="row" data-label="Notes">The target file size for compaction in bytes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_TARGET_FILE_SIZE_MULTIPLIER</code></td>
      <td scope="row" data-label="Default">2</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The target file size multiplier for each compaction level.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_THREAD_COUNT</code></td>
      <td scope="row" data-label="Default">Number of CPUs on machine</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The number of threads to start for flushing and compaction.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_UNIVERSAL_COMPRESSION_SIZE_PERCENT</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">-1</td>
      <td scope="row" data-label="Allowed values">An i32</td>
      <td scope="row" data-label="Notes">The percentage of output files to compress. <code>-1</code> compresses all of them. Only used when <code>SURREAL_ROCKSDB_COMPACTION_STYLE</code> is <code>universal</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_UNIVERSAL_MAX_MERGE_WIDTH</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">4,294,967,295 (no limit)</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">The largest number of files in a single merge. Only used when <code>SURREAL_ROCKSDB_COMPACTION_STYLE</code> is <code>universal</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_UNIVERSAL_MAX_SIZE_AMPLIFICATION_PERCENT</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">200</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">The largest acceptable storage amplification, as a percentage of the size of the live data. Only used when <code>SURREAL_ROCKSDB_COMPACTION_STYLE</code> is <code>universal</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_UNIVERSAL_MIN_MERGE_WIDTH</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">2</td>
      <td scope="row" data-label="Allowed values">A u32</td>
      <td scope="row" data-label="Notes">The smallest number of files in a single merge. Only used when <code>SURREAL_ROCKSDB_COMPACTION_STYLE</code> is <code>universal</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_UNIVERSAL_SIZE_RATIO</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">1</td>
      <td scope="row" data-label="Allowed values">An i32</td>
      <td scope="row" data-label="Notes">How much larger, as a percentage, a file can be than the files before it and still be picked for the same merge. Only used when <code>SURREAL_ROCKSDB_COMPACTION_STYLE</code> is <code>universal</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_UNIVERSAL_STOP_STYLE</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">total</td>
      <td scope="row" data-label="Allowed values">similar_size, total</td>
      <td scope="row" data-label="Notes">How RocksDB decides that a merge has collected enough files. Only used when <code>SURREAL_ROCKSDB_COMPACTION_STYLE</code> is <code>universal</code>.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_WAL_SIZE_LIMIT</code></td>
      <td scope="row" data-label="Default">0</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The write-ahead-log size limit in MiB.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_WHOLE_KEY_FILTERING</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether SST bloom filters also hold whole keys as well as prefixes. Whole keys make point lookups faster, at the cost of larger filters. Disabling it can suit a workload that mostly scans. Only used when <code>SURREAL_ROCKSDB_PREFIX_EXTRACTOR_ENABLED</code> is true.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_ROCKSDB_WRITE_BUFFER_SIZE</code></td>
      <td scope="row" data-label="Default">32 MiB (systems under 1 GiB), 64 MiB (up to 16 GiB), 128 MiB (others)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The amount of data each write buffer can build up in memory.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SYNC_DATA</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to sync writes to disk before acknowledgement. 2.x only: replaced in 3.0.0 by <code>SURREAL_DATASTORE_SYNC_DATA</code>.</td>
    </tr>
  </tbody>
</table>

### SurrealKV environment variables

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '50%'}}>Environment variable</th>
      <th scope="col" style={{width: '15%'}}>Default</th>
      <th scope="col" style={{width: '15%'}}>Allowed values</th>
      <th scope="col" style={{width: '30%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_BLOCK_CACHE_CAPACITY</code></td>
      <td scope="row" data-label="Default">Dynamically calculated via greater of ((system memory / 2) - 1 GiB) and 16MiB</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum log file size in bytes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_BLOCK_SIZE</code></td>
      <td scope="row" data-label="Default">65_536 (64 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The block size in bytes.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_ENABLE_VLOG</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to enable value log separation.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_GROUPED_COMMIT_MAX_BATCH_SIZE</code></td>
      <td scope="row" data-label="Default">4096</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The maximum number of transactions in a single grouped commit batch. This prevents unbounded memory growth while still allowing large batches for efficiency. Larger batches improve throughput but increase memory usage and commit latency.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_GROUPED_COMMIT_TIMEOUT</code></td>
      <td scope="row" data-label="Default">5ms</td>
      <td scope="row" data-label="Allowed values">A duration in nanoseconds</td>
      <td scope="row" data-label="Notes">The maximum wait time in nanoseconds before forcing a grouped commit. Ensures that transactions do not wait indefinitely under low concurrency and balances commit latency against write throughput.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_GROUPED_COMMIT_WAIT_THRESHOLD</code></td>
      <td scope="row" data-label="Default">12</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Threshold for deciding whether to wait for more transactions. If the current batch size is greater or equal to this threshold (and below SURREAL_SURREALKV_GROUPED_COMMIT_MAX_BATCH_SIZE), then the coordinator will wait up to SURREAL_SURREALKV_GROUPED_COMMIT_TIMEOUT to collect more transactions. Smaller batches are flushed immediately to preserve low latency.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_MAX_MEMTABLE_SIZE</code>_(since v3.1.0)_</td>
      <td scope="row" data-label="Default">Depends on system memory: 64 MiB below 1 GiB, 128 MiB below 4 GiB, 256 MiB below 16 GiB, 1 GiB below 64 GiB, and 4 GiB otherwise</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The size of the memory area that holds the memtable. A transaction larger than this fails, so raise it for large transactions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_VERSIONED_INDEX</code></td>
      <td scope="row" data-label="Default">false</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to enable versioned index. Only applies when versioning is enabled.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_VLOG_MAX_FILE_SIZE</code></td>
      <td scope="row" data-label="Default">64 MiB (systems under 4 GiB), 128 MiB (up to 16 GiB), 256 MiB (up to 64 GiB), 512 MiB (others)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The readahead buffer size used during compaction.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_SURREALKV_VLOG_THRESHOLD</code></td>
      <td scope="row" data-label="Default">4096 (4 KiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The value log threshold in bytes. Values larger than this are stored in the value log.</td>
    </tr>
  </tbody>
</table>

### TiKV environment variables

> [!IMPORTANT]
> These variables apply when SurrealDB is started with a `tikv://` endpoint for **local Community experimentation**. They are not the configuration surface for production multi-node HA. Prefer a managed cluster on [SurrealDB Cloud Scale](https://surrealdb.com/pricing/scale) or a self-hosted cluster with [SurrealDB Enterprise](https://surrealdb.com/enterprise). See [Run a multi-node cluster](/docs/running/multi-node.md).

<table>
  <thead>
    <tr>
      <th scope="col" style={{width: '50%'}}>Environment variable</th>
      <th scope="col" style={{width: '15%'}}>Default</th>
      <th scope="col" style={{width: '15%'}}>Allowed values</th>
      <th scope="col" style={{width: '30%'}}>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_API_VERSION</code></td>
      <td scope="row" data-label="Default">1</td>
      <td scope="row" data-label="Allowed values">A u8</td>
      <td scope="row" data-label="Notes">Which TiKV cluster API version to use.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_ASYNC_COMMIT</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to use asynchronous transactions.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_KEYSPACE</code></td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A string</td>
      <td scope="row" data-label="Notes">A string specifying the keyspace identifier for data isolation.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_GRPC_MAX_DECODING_MESSAGE_SIZE</code></td>
      <td scope="row" data-label="Default">4,194,304 (4 MiB)</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">Sets the maximum decoding size of a gRPC message.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_ONE_PHASE_COMMIT</code></td>
      <td scope="row" data-label="Default">true</td>
      <td scope="row" data-label="Allowed values">true, false</td>
      <td scope="row" data-label="Notes">Whether to use one-phase transaction commit.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_REQUEST_TIMEOUT</code></td>
      <td scope="row" data-label="Default">10</td>
      <td scope="row" data-label="Allowed values">A usize</td>
      <td scope="row" data-label="Notes">The duration in seconds for requests before they time out.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_TLS_CA_PATH</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A file path</td>
      <td scope="row" data-label="Notes">Path to the CA certificate used to verify the TiKV and PD servers. Setting all three <code>SURREAL_TIKV_TLS_*</code> variables switches the connection to mutual TLS (mTLS).</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_TLS_CERT_PATH</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A file path</td>
      <td scope="row" data-label="Notes">Path to the client certificate that SurrealDB presents during mTLS. It must be set together with the CA and key paths.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_TIKV_TLS_KEY_PATH</code>_(since v3.3.0)_</td>
      <td scope="row" data-label="Default">none</td>
      <td scope="row" data-label="Allowed values">A file path</td>
      <td scope="row" data-label="Notes">Path to the private key that matches the client certificate. It must be set together with the CA and certificate paths. If only some of the three paths are set, SurrealDB refuses to connect and reports which are missing.</td>
    </tr>
  </tbody>
</table>

### FoundationDB environment variables

> [!WARNING]
> FoundationDB support was removed in SurrealDB 3.0.0. These variables apply to 2.x only.

<table>
  <thead>
    <tr>
      <th scope="col">Environment variable</th>
      <th scope="col">Default value</th>
      <th scope="col">Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_FOUNDATIONDB_TRANSACTION_MAX_RETRY_DELAY</code></td>
      <td scope="row" data-label="Default">500</td>
      <td scope="row" data-label="Notes">The maximum delay between transaction retries in milliseconds.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_FOUNDATIONDB_TRANSACTION_RETRY_LIMIT</code></td>
      <td scope="row" data-label="Default">5</td>
      <td scope="row" data-label="Notes">The maximum number of times a transaction can be retried.</td>
    </tr>
    <tr>
      <td scope="row" data-label="Env var"><code>SURREAL_FOUNDATIONDB_TRANSACTION_TIMEOUT</code></td>
      <td scope="row" data-label="Default">5000</td>
      <td scope="row" data-label="Notes">The maximum transaction timeout in milliseconds.</td>
    </tr>
  </tbody>
</table>

## SurrealDB Cloud environment variables

Instances on SurrealDB Cloud are not started with a CLI command or environment variables. Instead, they can be set from [SurrealDB Studio](/docs/manage/instances/configure.md) or with [`surreal cloud`](/docs/reference/cli/cloud.md).
