Skip to main content

SurrealDB

SurrealDB

SurrealDB is a multi-model database for modern applications, combining document, graph, and relational capabilities in a single platform.

Overview

  • Versions: 2.1, 2.0, 1.5 (default: 2.1)
  • Default Port: 8000
  • Cluster Support: No (Single node only)
  • Use Cases: Multi-model data, modern applications, real-time APIs
  • Features: Document store, graph queries, relational joins, real-time subscriptions

Key Features

  • Multi-Model: Document, graph, and relational models in one database
  • SurrealQL: Powerful query language combining SQL-like syntax with graph traversals
  • Real-Time Subscriptions: Live queries for real-time data updates
  • Schema Flexibility: Schemaless or schemafull modes
  • Built-in Auth: Row-level security and authentication
  • ACID Transactions: Full transaction support
  • Record Links: Native graph-style relationships between records
  • Computed Fields: Define fields that auto-compute from other data
  • Events and Triggers: React to data changes automatically

Resources

Choose the add-on's resources on the create form:

SettingOptionsDefault
CPU (vCPU)Free entry (e.g., 0.5, 1, 2)0.5
Memory1GB, 2GB, 4GB, 8GB, 16GB1GB
Disk Space1GB, 5GB, 10GB, 20GB, 50GB, 100GB10GB
GPU Count0-8 (0 for CPU-only)0

Creating a SurrealDB Add-on

  1. Navigate to Add-ons and click Create Add-on
  2. On the Create New Add-on page, select SurrealDB as the type
  3. Choose a version (2.1, 2.0, or 1.5)
  4. Configure:
    • Add-on Label (required): descriptive name (e.g., "app-database")
    • Description (optional): purpose and notes
    • Resources: CPU, memory, and disk for your workload
  5. Optionally enable automatic backups:
    • Schedule: Hourly, Daily, Weekly, or Monthly
    • Retention: number of backups to keep (1-30, default 7)
  6. Click Create Add-on

Connection Information

Once the add-on is running, the Connection tab of the add-on details page shows the internal host (for apps), port, username, and password. The same details are exposed to your apps via STRONGLY_SERVICES, where the connection string uses the WebSocket RPC endpoint:

ws://username:password@host:8000/rpc

Credentials are auto-generated during add-on creation. The username is a randomly generated string (e.g., user_a1b2c3d4), and the password is a 32-character random secret.

Accessing Connection Details

In STRONGLY_SERVICES, add-ons are grouped by type under services.addons, and each entry is one provisioned instance:

{
"id": "addon-abc123defg",
"name": "app-database",
"type": "surrealdb",
"category": "add-on",
"status": "running",
"version": "2.1",
"connection": {
"connection_string": "ws://user_a1b2c3d4:<password>@<internal-host>:8000/rpc",
"uri": "ws://user_a1b2c3d4:<password>@<internal-host>:8000/rpc",
"host": "<internal-host>",
"port": 8000
},
"auth": {
"method": "username_password",
"credentials": { "username": "user_a1b2c3d4", "password": "<password>" }
},
"limits": { "max_connections": 100, "storage_gb": 10 },
"metadata": { "cpu": "0.5", "memory": "1GB", "disk": "10GB", "backup_enabled": false }
}
import os
import json
from surrealdb import Surreal

# Parse STRONGLY_SERVICES
services = json.loads(os.environ['STRONGLY_SERVICES'])

# Pick your SurrealDB add-on by name (the label you gave it)
surreal_addon = next(
a for a in services['services']['addons']['surrealdb']
if a['name'] == 'app-database'
)

conn = surreal_addon['connection']
auth = surreal_addon['auth']['credentials']

# Connect using host and port
async def main():
db = Surreal(f"ws://{conn['host']}:{conn['port']}/rpc")
await db.connect()

# Sign in
await db.signin({
"user": auth['username'],
"pass": auth['password']
})

# Select namespace and database
await db.use("test", "test")

# Create a record
await db.create("person", {
"name": "Alice",
"age": 30,
"active": True
})

# Query records
result = await db.query("SELECT * FROM person WHERE active = true")
print(result)

await db.close()

import asyncio
asyncio.run(main())

SurrealQL Query Language

SurrealQL combines SQL-like syntax with graph traversals and modern features.

Basic CRUD Operations

-- Create a record with auto-generated ID
CREATE person SET name = 'Alice', age = 30, active = true;

-- Create with specific ID
CREATE person:alice SET name = 'Alice', age = 30, active = true;

-- Select all records
SELECT * FROM person;

-- Select with conditions
SELECT * FROM person WHERE age > 25 AND active = true;

-- Update a record
UPDATE person:alice SET age = 31, updated_at = time::now();

-- Update with merge
UPDATE person:alice MERGE { email: 'alice@example.com' };

-- Delete a record
DELETE person:alice;

-- Delete with condition
DELETE person WHERE active = false;

SurrealDB supports native graph-style relationships:

-- Create records with relationships
CREATE person:alice SET name = 'Alice';
CREATE person:bob SET name = 'Bob';
CREATE company:acme SET name = 'Acme Corp';

-- Create a relationship
RELATE person:alice->works_at->company:acme
SET since = '2020-01-01', role = 'Engineer';

RELATE person:alice->knows->person:bob
SET since = '2019-06-15';

-- Traverse relationships
SELECT ->works_at->company.name FROM person:alice;

-- Reverse traversal
SELECT <-works_at<-person.name FROM company:acme;

-- Multi-hop traversal
SELECT ->knows->person->works_at->company.name FROM person:alice;

-- Query relationships with conditions
SELECT ->works_at WHERE since > '2019-01-01' FROM person;

Subqueries and Advanced Queries

-- Subquery
SELECT *, (SELECT count() FROM ->works_at GROUP ALL) AS job_count
FROM person;

-- Aggregation
SELECT
count() AS total,
math::mean(age) AS avg_age,
math::min(age) AS youngest,
math::max(age) AS oldest
FROM person
GROUP ALL;

-- Group by
SELECT
active,
count() AS total,
math::mean(age) AS avg_age
FROM person
GROUP BY active;

-- Order and limit
SELECT * FROM person
ORDER BY age DESC
LIMIT 10
START 20;

-- FETCH to resolve links
SELECT * FROM person FETCH works_at;

Computed Fields and Events

-- Define a table with computed fields
DEFINE TABLE person SCHEMAFULL;
DEFINE FIELD name ON person TYPE string;
DEFINE FIELD first_name ON person TYPE string;
DEFINE FIELD last_name ON person TYPE string;
DEFINE FIELD full_name ON person VALUE string::concat($value.first_name, ' ', $value.last_name);

-- Define an event
DEFINE EVENT person_created ON TABLE person WHEN $event = "CREATE" THEN (
CREATE audit SET
table = 'person',
action = 'create',
record = $after.id,
timestamp = time::now()
);

Permissions and Auth

-- Define a scope for authentication
DEFINE SCOPE user SESSION 24h
SIGNUP (CREATE user SET email = $email, password = crypto::argon2::generate($password))
SIGNIN (SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(password, $password));

-- Define permissions on tables
DEFINE TABLE post SCHEMALESS
PERMISSIONS
FOR select WHERE published = true OR author = $auth.id
FOR create WHERE $auth.id IS NOT NONE
FOR update WHERE author = $auth.id
FOR delete WHERE author = $auth.id;

Common Use Cases

Document Store

-- Store flexible documents
CREATE article SET
title = 'Getting Started with SurrealDB',
content = 'SurrealDB is a multi-model database...',
tags = ['database', 'tutorial', 'surrealdb'],
metadata = {
author: 'Alice',
published: true,
views: 0,
created_at: time::now()
};

-- Query with nested fields
SELECT * FROM article WHERE metadata.published = true;

-- Full-text search
SELECT * FROM article WHERE title @@ 'SurrealDB';

Graph Database

-- Social network
CREATE user:alice SET name = 'Alice';
CREATE user:bob SET name = 'Bob';
CREATE user:charlie SET name = 'Charlie';

RELATE user:alice->follows->user:bob;
RELATE user:bob->follows->user:charlie;
RELATE user:charlie->follows->user:alice;

-- Find mutual follows (friends)
SELECT id, name,
->follows->user AS following,
<-follows<-user AS followers
FROM user;

-- Friend recommendations (friends of friends)
SELECT ->follows->user->follows->user AS suggestions
FROM user:alice
WHERE suggestions != user:alice;

Real-Time Applications

-- Live query (WebSocket)
LIVE SELECT * FROM messages WHERE channel = 'general';

-- The client receives real-time updates when:
-- - New messages are created
-- - Existing messages are updated
-- - Messages are deleted

Backup & Restore

Backup Configuration

  • Tool: surreal export
  • Format: .surql
  • Includes: Schema, data, relationships
  • Storage: the platform's S3 backup storage

Manual Backup

  1. Go to the add-on details page
  2. Open the Backup tab and click Create Manual Backup (the add-on must be running)
  3. The Backup tab shows the last backup time when complete

Scheduled Backups

Configure during add-on creation or on the Backup tab:

  • Hourly: For critical data with frequent changes
  • Daily: Recommended for most production workloads
  • Weekly/Monthly: For less frequently changing data
  • Retention: number of backups to keep (3, 7, 14, or 30 on the Backup tab)

Performance Optimization

Indexing

-- Create an index
DEFINE INDEX email_idx ON person FIELDS email UNIQUE;

-- Create a composite index
DEFINE INDEX name_age_idx ON person FIELDS name, age;

-- Create a search index for full-text search
DEFINE ANALYZER custom TOKENIZERS blank FILTERS lowercase, snowball(english);
DEFINE INDEX content_search ON article FIELDS content SEARCH ANALYZER custom;

Query Optimization

-- Use specific record IDs when possible (fastest)
SELECT * FROM person:alice;

-- Use indexes for filtering
SELECT * FROM person WHERE email = 'alice@example.com';

-- Limit result sets
SELECT * FROM person LIMIT 100;

-- Use FETCH sparingly - only when you need linked data
SELECT * FROM person FETCH works_at;

Monitoring

The Metrics tab on the add-on details page shows:

  • CPU Usage: CPU utilization percentage
  • Memory Usage: memory utilization percentage
  • Disk Space: disk utilization percentage
  • Network I/O: current throughput
  • Request Stats: connections per minute and average response time
  • Instance Health: instance count and uptime

Best Practices

  1. Use Record Links: Leverage native graph relationships instead of foreign keys
  2. Define Schemas: Use SCHEMAFULL for production tables requiring data validation
  3. Index Strategically: Create indexes on frequently queried fields
  4. Use Namespaces: Organize data into logical namespaces and databases
  5. Leverage Live Queries: Use real-time subscriptions for reactive UIs
  6. Batch Operations: Insert multiple records in a single transaction
  7. Set Permissions: Define table-level permissions for security
  8. Backup Regularly: Enable daily backups for production databases
  9. Monitor Memory: Watch memory usage as data grows

Troubleshooting

Connection Issues

# Test connection via HTTP
import requests

response = requests.post(
f'http://{host}:8000/sql',
headers={
'Accept': 'application/json',
'NS': 'test',
'DB': 'test',
},
auth=(username, password),
data='INFO FOR DB;'
)
print(response.json())

Query Issues

-- Check table info
INFO FOR TABLE person;

-- Check database info
INFO FOR DB;

-- Check namespace info
INFO FOR NS;

Support

For issues or questions:

  • Check add-on logs in the Logs tab of the add-on details page
  • Review SurrealDB official documentation
  • Contact Strongly support through the platform