Home Database SurrealDB: Multi-Model Database – SQL, Graph & Documents Combined
Intermediate 4 min · July 13, 2026

SurrealDB: Multi-Model Database – SQL, Graph & Documents Combined

Learn SurrealDB, a multi-model database that unifies SQL, document, and graph paradigms.

N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Lessons pulled from things that broke in production.

Follow
Production
production tested
July 13, 2026
last updated
2,165
articles · all by Naren
Before you start⏱ 15-20 min read
  • Basic understanding of SQL (SELECT, INSERT, UPDATE, DELETE).
  • Familiarity with NoSQL concepts (documents, graphs).
  • Docker installed for local setup.
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • SurrealDB is a multi-model database combining SQL, document, and graph features.
  • It uses a unique query language (SurrealQL) that feels like SQL but supports nested objects and graph traversals.
  • Built-in support for real-time subscriptions, row-level security, and schema flexibility.
  • Ideal for applications needing relational, document, and graph capabilities without separate databases.
✦ Definition~90s read
What is SurrealDB?

SurrealDB is a multi-model database that combines relational, document, and graph paradigms into a single engine with a SQL-like query language.

Imagine a Swiss Army knife for data: instead of carrying a separate notebook (SQL), a filing cabinet (documents), and a map (graph), SurrealDB gives you one tool that can do all three.
Plain-English First

Imagine a Swiss Army knife for data: instead of carrying a separate notebook (SQL), a filing cabinet (documents), and a map (graph), SurrealDB gives you one tool that can do all three. You can write a query that fetches a user, their posts (like a document), and the friends they're connected to (like a graph) in a single request.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

In the modern application landscape, data rarely fits neatly into a single paradigm. A social media app might need relational tables for user accounts, document stores for flexible post content, and graph queries for friend recommendations. Traditionally, developers stitch together multiple databases (e.g., PostgreSQL + MongoDB + Neo4j), leading to complex data synchronization, increased latency, and higher operational costs.

SurrealDB emerges as a solution: a multi-model database that natively supports relational, document, and graph data models within a single engine. It uses SurrealQL, a query language that extends SQL with constructs for nested objects and graph traversals. This means you can define a table with a flexible schema, embed documents, and traverse relationships—all in one query.

In this tutorial, you'll learn how to set up SurrealDB, model data using its multi-model capabilities, write queries that combine SQL, document, and graph operations, and apply best practices for production. We'll also explore a real-world production incident and provide debugging guides to help you avoid common pitfalls.

1. Setting Up SurrealDB

SurrealDB can run as a single-node or in a distributed cluster. For development, the easiest way is to use the Docker image. First, pull the image and start a container:

``bash docker run --rm -p 8000:8000 surrealdb/surrealdb:latest start ``

This starts SurrealDB with an in-memory store. For persistent storage, mount a volume. Once running, connect using the SurrealQL CLI or any HTTP client. The default endpoint is http://localhost:8000.

``bash surreal sql --endpoint http://localhost:8000 --namespace test --database test ``

You can also use the REST API. For example, to create a record:

``bash curl -X POST http://localhost:8000/sql -H "Content-Type: text/plain" -d "CREATE user SET name = 'Alice', age = 30" ``

Now you're ready to explore multi-model features.

setup.shBASH
1
2
docker run --rm -p 8000:8000 surrealdb/surrealdb:latest start
surreal sql --endpoint http://localhost:8000 --namespace test --database test
Output
Connected to SurrealDB at http://localhost:8000
💡Namespace vs Database
📊 Production Insight
In production, use persistent volumes and consider running SurrealDB in a cluster for high availability.
🎯 Key Takeaway
SurrealDB is easy to set up with Docker; use the CLI or REST API to interact.

2. Understanding SurrealQL: SQL with Superpowers

SurrealQL is the query language for SurrealDB. It looks like SQL but adds constructs for nested objects and graph traversals. For example, you can create a record with embedded data:

``sql CREATE user SET name = 'Bob', address = { street: '123 Main', city: 'NYC' }; ``

This creates a document with a nested object. You can also define relationships using the RELATE keyword:

``sql RELATE $user->friends->$friend SET since = '2024-01-01'; ``

This creates an edge between two records. The edge itself can have properties (like since).

``sql SELECT ->friends->name FROM user WHERE id = $user; ``

This traverses the graph from a user to their friends and returns the friends' names.

SurrealQL also supports standard SQL operations like WHERE, ORDER BY, GROUP BY, and JOIN (though joins are less common due to graph traversal).

surrealql_basics.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
-- Create a user with nested address
CREATE user SET name = 'Bob', address = { street: '123 Main', city: 'NYC' };

-- Create another user
CREATE user SET name = 'Alice';

-- Relate them as friends
LET $bob = (SELECT id FROM user WHERE name = 'Bob');
LET $alice = (SELECT id FROM user WHERE name = 'Alice');
RELATE $bob->friends->$alice SET since = '2024-01-01';

-- Query friends of Bob
SELECT ->friends->name FROM user WHERE name = 'Bob';
Output
[{ "->friends->name": ["Alice"] }]
🔥Graph Traversal Syntax
📊 Production Insight
Graph traversals can be expensive if not indexed. Always index fields used in WHERE clauses on edges.
🎯 Key Takeaway
SurrealQL extends SQL with nested objects and graph traversals using RELATE and arrow syntax.

3. Multi-Model Data Modeling

SurrealDB allows you to mix models in a single table. For example, a post table can have a flexible schema: some posts are text, others are images with metadata. You can define fields with types, but also allow extra fields:

``sql DEFINE TABLE post SCHEMAFULL; DEFINE FIELD title ON post TYPE string; DEFINE FIELD content ON post TYPE string; DEFINE FIELD metadata ON post TYPE object; ``

With SCHEMAFULL, only defined fields are allowed. Use SCHEMALESS for flexibility. You can also define indexes on fields.

For graph relationships, define edges as separate tables or use the RELATE syntax directly. Edges are stored in a special table named after the relation (e.g., friends). You can query edges like any table:

``sql SELECT * FROM friends WHERE in = $user_id; ``

This gives you all edges where the user is the source.

To model a many-to-many relationship, use edges with properties. For example, a user can have many friends, and each friendship has a since date.

modeling.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
-- Define a schemafull table for posts
DEFINE TABLE post SCHEMAFULL;
DEFINE FIELD title ON post TYPE string;
DEFINE FIELD content ON post TYPE string;
DEFINE FIELD metadata ON post TYPE object;

-- Create a post with metadata
CREATE post SET title = 'My First Post', content = 'Hello', metadata = { image: 'url', tags: ['intro'] };

-- Query posts with specific metadata
SELECT * FROM post WHERE metadata.tags CONTAINS 'intro';
Output
[{ "id": "post:1", "title": "My First Post", "content": "Hello", "metadata": { "image": "url", "tags": ["intro"] } }]
⚠ Schema Changes
📊 Production Insight
In production, prefer SCHEMAFULL to avoid data inconsistency. Use indexes on fields used in WHERE and graph traversals.
🎯 Key Takeaway
Use SCHEMAFULL for strict schemas and SCHEMALESS for flexibility. Edges are stored in relation tables.

4. Advanced Queries: Combining SQL, Documents, and Graphs

One of SurrealDB's strengths is combining paradigms in a single query. For example, you can fetch a user, their posts (documents), and their friends' posts (graph) in one statement:

``sql SELECT name, (SELECT title, content FROM post WHERE author = $parent.id) AS posts, (SELECT ->friends->post.title FROM user WHERE id = $parent.id) AS friends_posts FROM user WHERE id = $user_id; ``

This uses subqueries with $parent to reference the outer record. The result is a nested JSON structure.

``sql SELECT ->friends->(post WHERE created_at > '2024-01-01')->title FROM user WHERE name = 'Bob'; ``

This returns titles of posts created after a date by Bob's friends.

SurrealDB also supports full-text search on string fields:

``sql SELECT * FROM post WHERE content @@ 'search term'; ``

This uses the built-in search index.

advanced_query.sqlSQL
1
2
3
4
5
6
-- Get user with their posts and friends' posts
SELECT 
    name,
    (SELECT title, content FROM post WHERE author = $parent.id) AS posts,
    (SELECT ->friends->post.title FROM user WHERE id = $parent.id) AS friends_posts
FROM user WHERE id = 'user:1';
Output
[{ "name": "Bob", "posts": [{ "title": "My Post" }], "friends_posts": ["Alice's Post"] }]
💡Using $parent
📊 Production Insight
Complex nested queries can be slow; use indexes and limit results. Consider denormalizing frequently accessed data.
🎯 Key Takeaway
Combine subqueries and graph traversals to fetch relational, document, and graph data in one query.

5. Real-Time Subscriptions and Security

SurrealDB supports real-time subscriptions via WebSocket. You can listen for changes on a table or query:

``sql LIVE SELECT * FROM user; ``

This returns a live query ID. The client receives updates when records are created, updated, or deleted. This is useful for building reactive applications.

For security, SurrealDB has a built-in row-level security system. You can define permissions on tables and fields:

``sql DEFINE TABLE user PERMISSIONS FOR select WHERE id = $auth.id; ``

This ensures users can only see their own record. The $auth variable contains the authenticated user's details.

You can also define scopes for authentication and token generation.

realtime_security.sqlSQL
1
2
3
4
5
-- Define a live query
LIVE SELECT * FROM user;

-- Define row-level security
DEFINE TABLE user PERMISSIONS FOR select WHERE id = $auth.id;
Output
Live query ID: 'live:1'
🔥Authentication
📊 Production Insight
Be cautious with live queries on large tables; they can cause high memory usage. Use filters to limit scope.
🎯 Key Takeaway
SurrealDB supports real-time subscriptions and row-level security, making it suitable for modern web apps.

6. Performance Tuning and Indexing

Like any database, indexing is crucial for performance. SurrealDB supports several index types:

  • UNIQUE index for unique values
  • SEARCH index for full-text search
  • BTREE index for range queries

``sql DEFINE INDEX idx_user_name ON user COLUMNS name UNIQUE; ``

For graph traversals, index the fields used in edge queries. For example, if you often query edges by in or out, index those:

``sql DEFINE INDEX idx_friends_in ON friends COLUMNS in; ``

``sql EXPLAIN SELECT * FROM user WHERE name = 'Bob'; ``

This shows whether an index is used.

Also consider using FETCH to eagerly load related records and avoid N+1 queries:

``sql SELECT * FROM user FETCH friends; ``

This loads the friends' records in one go.

indexing.sqlSQL
1
2
3
4
5
6
7
8
-- Create a unique index on user name
DEFINE INDEX idx_user_name ON user COLUMNS name UNIQUE;

-- Create an index on friends.in
DEFINE INDEX idx_friends_in ON friends COLUMNS in;

-- Explain a query
EXPLAIN SELECT * FROM user WHERE name = 'Bob';
Output
[{ "detail": "Index 'idx_user_name' used" }]
⚠ Index Maintenance
📊 Production Insight
Monitor slow queries and add indexes accordingly. Use FETCH to reduce round trips.
🎯 Key Takeaway
Index fields used in WHERE and graph traversals. Use EXPLAIN to verify index usage.

7. Production Best Practices

Running SurrealDB in production requires careful planning. Here are key practices:

  1. Backup regularly: Use BACKUP command or snapshot the data directory.
  2. Monitor metrics: SurrealDB exposes Prometheus metrics; integrate with monitoring tools.
  3. Use connection pooling: For high concurrency, use a connection pooler like PgBouncer (though SurrealDB uses HTTP/WebSocket, so manage connections wisely).
  4. Schema migrations: Use version-controlled migration scripts. Test on staging first.
  5. Security: Enable authentication, use HTTPS, and define strict permissions.
  6. Scaling: SurrealDB supports clustering; distribute data across nodes for horizontal scaling.

``sql BACKUP INTO 's3://bucket/backup'; ``

For disaster recovery, have a replica in a different region.

backup.sqlSQL
1
2
-- Backup to S3
BACKUP INTO 's3://my-bucket/surrealdb-backup';
Output
Backup completed successfully.
💡Migration Tools
📊 Production Insight
Always have a rollback plan. Use feature flags to toggle new schema changes.
🎯 Key Takeaway
Plan for backups, monitoring, security, and schema migrations. Test changes in staging.
● Production incidentPOST-MORTEMseverity: high

The Case of the Missing Graph Edges: A SurrealDB Production Outage

Symptom
Users saw empty friend suggestion lists; API returned 200 with empty arrays.
Assumption
The developer assumed that adding a new field to a table would not affect existing graph edges.
Root cause
The new field definition included a DEFAULT value that caused SurrealDB to re-index the table, inadvertently dropping all edges that referenced the table.
Fix
Rolled back the schema change, then applied it with ALTER TABLE ... NOINDEX to prevent re-indexing, followed by manual edge re-creation.
Key lesson
  • Always test schema changes on a staging environment with production-like data.
  • Understand that altering a table in SurrealDB can trigger re-indexing, which may drop edges.
  • Use ALTER TABLE ... NOINDEX when adding fields that don't need indexing.
  • Monitor edge counts before and after schema migrations.
  • Have a rollback plan for every production change.
Production debug guideSymptom to Action4 entries
Symptom · 01
Query returns empty results for graph traversal
Fix
Check if edges exist: SELECT * FROM edges WHERE in = target_id
Symptom · 02
Document fields missing in query output
Fix
Verify schema: INFO TABLE tablename to see field definitions
Symptom · 03
Slow queries after schema change
Fix
Run EXPLAIN SELECT ... to see query plan and check for missing indexes
Symptom · 04
Real-time subscription not receiving updates
Fix
Ensure the table has LIVE SELECT permission and the client is connected via WebSocket
★ Quick Debug Cheat SheetCommon SurrealDB issues and immediate actions
Edge not found
Immediate action
Check edge table
Commands
SELECT * FROM edges WHERE in = $target
SELECT * FROM $target->friends->$target
Fix now
Re-create edge: RELATE $user->friends->$friend
Field missing in document+
Immediate action
Check schema
Commands
INFO TABLE users
SELECT * FROM users WHERE id = $id
Fix now
Add field: DEFINE FIELD email ON users TYPE string
Query timeout+
Immediate action
Check indexes
Commands
EXPLAIN SELECT * FROM users WHERE name = 'John'
DEFINE INDEX idx_name ON users COLUMNS name
Fix now
Add index and retry
FeatureSurrealDBPostgreSQLMongoDBNeo4j
Data ModelsRelational, Document, GraphRelationalDocumentGraph
Query LanguageSurrealQL (SQL-like)SQLMQLCypher
Real-time SubscriptionsBuilt-inVia extensionsChange streamsNo
Row-level SecurityBuilt-inVia policiesNoNo
ACID TransactionsYesYesYes (since 4.0)Yes
⚙ Quick Reference
7 commands from this guide
FileCommand / CodePurpose
setup.shdocker run --rm -p 8000:8000 surrealdb/surrealdb:latest start1. Setting Up SurrealDB
surrealql_basics.sqlCREATE user SET name = 'Bob', address = { street: '123 Main', city: 'NYC' };2. Understanding SurrealQL
modeling.sqlDEFINE TABLE post SCHEMAFULL;3. Multi-Model Data Modeling
advanced_query.sqlSELECT4. Advanced Queries
realtime_security.sqlLIVE SELECT * FROM user;5. Real-Time Subscriptions and Security
indexing.sqlDEFINE INDEX idx_user_name ON user COLUMNS name UNIQUE;6. Performance Tuning and Indexing
backup.sqlBACKUP INTO 's3://my-bucket/surrealdb-backup';7. Production Best Practices

Key takeaways

1
SurrealDB unifies SQL, document, and graph models, reducing the need for multiple databases.
2
Use SurrealQL with arrow syntax for graph traversals and nested objects for documents.
3
Index fields used in WHERE and edge queries to ensure performance.
4
Leverage real-time subscriptions and row-level security for modern applications.
5
Follow production best practices
backups, monitoring, schema migrations, and security.

Common mistakes to avoid

4 patterns
×

Not indexing edge fields

×

Using SCHEMALESS in production

×

Forgetting to use $parent in subqueries

×

Not handling schema migrations carefully

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
Explain the multi-model approach of SurrealDB. How does it differ from u...
Q02JUNIOR
How do you define a graph relationship in SurrealDB? Provide an example.
Q03SENIOR
What are the performance considerations when using graph traversals in S...
Q01 of 03SENIOR

Explain the multi-model approach of SurrealDB. How does it differ from using separate databases?

ANSWER
SurrealDB combines relational, document, and graph models in one engine. Instead of managing multiple databases, you use a single query language (SurrealQL) to handle all data types. This reduces complexity, latency, and operational overhead.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Can SurrealDB replace PostgreSQL and MongoDB?
02
How does SurrealDB handle joins?
03
Is SurrealDB ACID compliant?
04
What is the difference between SCHEMAFULL and SCHEMALESS?
05
Can I use SurrealDB with my existing SQL tools?
N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Lessons pulled from things that broke in production.

Follow
Verified
production tested
July 13, 2026
last updated
2,165
articles · all by Naren
🔥

That's NoSQL. Mark it forged?

4 min read · try the examples if you haven't

Previous
DynamoDB Advanced: Single-Table Design and DAX
20 / 27 · NoSQL
Next
Couchbase: Distributed NoSQL Database