SurrealDB separates the query engine (compute) from the storage layer. The engine speaks one query language and exposes one API, while the storage layer decides how data is persisted, replicated and scaled. Because the two are decoupled, the same database, queries and SDK calls work from an embedded edge application through to a distributed cloud cluster.
![Diagram of SurrealDB's layered architecture: clients connect through [client].surrealdb.com to multiple compute nodes, all backed by centralised storage on AWS S3.](/docs/assets/static/architecture-light.zHAJ9yOf.png)
![Diagram of SurrealDB's layered architecture: clients connect through [client].surrealdb.com to multiple compute nodes, all backed by centralised storage on AWS S3.](/docs/assets/static/architecture-dark.kfM-gGLg.png)
This page describes the two layers, how the data models share a single store, and how a SurrealDB deployment is organised.
Query layer
The query layer handles client requests and coordinates work against storage:
Parses and executes SurrealQL
Authenticates connections and sessions, for example through
SIGNINand access methodsEnforces table- and field-level
PERMISSIONSas records are read and writtenPlans index-backed queries, updates index entries on writes, and coordinates transactions against storage
Incoming SurrealQL passes through a parser, an executor that groups statements into transactions, an iterator that plans data access and fetches keys from storage, and a document processor that applies permissions and persists changes through the storage API.
Every transaction runs under snapshot isolation with write conflict detection on commit, whichever storage backend sits underneath. A SELECT ... FOR UPDATE read extends that detection to records the transaction reads without writing.
Storage layer
The storage layer handles persistence and durability. It determines deployment characteristics such as scalability, temporal versioning, replication and fault tolerance. SurrealDB integrates with several engines depending on how you run the database:
| Concern | Typical engine |
|---|---|
| Single-node production | RocksDB (recommended for single node) |
| Single-node or embedded | SurrealKV (beta) |
| In-memory server or embedded | SurrealMX |
| Browser persistence | IndexedDB |
| Distributed multi-node | Shared distributed storage on SurrealDB Cloud Scale and self-hosted Enterprise |
Each engine must support transactional read and write of individual keys and key ranges. That is the whole contract, which is why the query layer can offer identical semantics across every deployment model.
One store for every data model
SurrealDB is a document database at its core. Each record is a document held on a key-value engine, and it can carry arbitrary nested objects and arrays.
The other models come from how those keys are laid out rather than from separate subsystems:
Record IDs sort in a defined order, so a range read over a table returns records in that order. This is what makes time-series access a range scan rather than a scan-and-filter.
Graph edges are records of their own, created with
RELATE. Traversal reads the edge table by key, so a graph query stays a series of key lookups.Indexes for vector and full-text search are index entries in the same store, maintained by the query layer as records change.
One consequence matters for application design: a write that touches a document, its edges and its index entries is one transaction against one store, so those parts cannot drift apart.
System structure
SurrealDB is a multi-tenant platform. Resources nest in four levels, and each level has its own DEFINE statement:
| Level | Statement | Purpose |
|---|---|---|
| Namespace | DEFINE NAMESPACE | Isolation for an organisation, department or team. No limit on the number of namespaces. |
| Database | DEFINE DATABASE | The unit that holds data. Each database has its own tables, indexes, schema, settings and permissions. No limit per namespace. |
| Table | DEFINE TABLE | A collection of records. Called a collection in some other systems. |
| Field | DEFINE FIELD | A typed field on a table, with optional assertions and permissions. |
A row or document in SurrealDB is called a record, and a column is called a field. Records are created, read, updated and deleted, with further statements for common patterns: UPSERT writes a record whether or not it already exists, and RELATE links two records through an edge table.
Namespaces and databases
A namespace is the outer container. It holds databases and nothing else, which makes it the natural boundary in multi-tenant deployments where separate applications or teams share one instance or cluster. Permissions and access methods can be granted at namespace level rather than per database.
A database sits inside a namespace and is where data lives: tables, records, indexes, events, functions and access methods. Most work happens here.
Both are defined with a unique name and an optional comment. The USE statement switches the session from one namespace or database to another.
DEFINE NAMESPACE dev_namespace COMMENT "Internal use only: do not use in prod";
USE NAMESPACE dev_namespace;
-- Now inside 'dev_namespace', define a database within it
DEFINE DATABASE dev_db_1 COMMENT "First of many dev databases";Multiple access methods can be defined on a namespace or a database. The record access method authenticates your end users against your own tables, down to field level.
Inspecting a deployment
The INFO statement reports what exists at each level:
INFO FOR ROOT: namespaces, root users, and system information such as allocated memory and physical cores.INFO FOR NAMESPACE: the namespace's databases, users and access methods.INFO FOR DATABASE: the database's tables, users, accesses, functions, analysers and more.
Each resource is reported as the DEFINE statement that would recreate it, which makes the output a readable snapshot of the schema:
{
accesses: { },
analyzers: {
blank_snowball: 'DEFINE ANALYZER blank_snowball TOKENIZERS BLANK FILTERS LOWERCASE, SNOWBALL(ENGLISH)'
},
functions: {
pound_to_usd: 'DEFINE FUNCTION fn::pound_to_usd($price: number) -> float { $price * 1.26f } PERMISSIONS FULL'
},
tables: {
order: 'DEFINE TABLE order TYPE RELATION IN person OUT product SCHEMAFULL PERMISSIONS NONE',
user: 'DEFINE TABLE user TYPE ANY SCHEMALESS PERMISSIONS NONE'
},
users: {
Boris: "DEFINE USER Boris ON DATABASE PASSHASH '[REDACTED]' ROLES VIEWER DURATION FOR TOKEN 1h, FOR SESSION NONE"
}
}Further INFO statements report the state of individual tables, users and indexes.
Deployment models
The separation of compute from storage gives four ways to run the same database:
Embedded, in memory through SurrealMX, on disk through RocksDB or SurrealKV, or in the browser through IndexedDB.
Single-node self-hosted, on RocksDB, or on SurrealKV while it is in beta.
Multi-node self-hosted, on managed Kubernetes such as EKS, GKE or AKS.
Managed, through managed instances, from single-node Start instances to multi-node Scale clusters on distributed storage.
Development can begin on an embedded or single-node deployment and move to a cluster later without changing application code or queries.
For storage trade-offs and how to choose a model, see Deployment models.
Where SurrealDB sits in your stack
SurrealDB works as a conventional database behind a backend service, using the SDKs for Go, Python, Rust, C, Java, .NET, Node.js or PHP.
It can also serve a frontend directly. Table-, record- and field-level permissions, combined with record access authentication, let a browser or mobile client connect to the database and still only see the data it is entitled to. The JavaScript SDK, WebAssembly and the framework integrations for React, Next.js, Vue, Svelte and others support this arrangement.
Both approaches use the same query language and the same permission model, so a project can start with one and add the other later.