A developer told me: 'I used PostgreSQL for relational data, Redis for caching, Neo4j for graph queries, and Elasticsearch for search. Four databases, four connections, four bills.' SurrealDB does all four in one.
What SurrealDB Offers
SurrealDB (open source, free):
- Document + Graph + Relational — one database, all models
- SurrealQL — SQL-like query language with graph traversals
- Real-time subscriptions — WebSocket live queries
- Built-in auth — user scoping and permissions
- HTTP & WebSocket API — REST and real-time
- Embedded mode — runs in-process (like SQLite)
- Multi-tenancy — namespace > database > table scoping
- Full-text search — built-in
- Single binary, runs anywhere
Quick Start
# Install
curl -sSf https://install.surrealdb.com | sh
# Start server
surreal start --user root --pass root memory
# API at http://localhost:8000
REST API
# Execute a query
curl -X POST 'http://localhost:8000/sql' \
-H 'Accept: application/json' \
-H 'NS: myapp' \
-H 'DB: main' \
-u 'root:root' \
-d 'SELECT * FROM user WHERE age > 18 ORDER BY name LIMIT 10'
# Create a record
curl -X POST 'http://localhost:8000/key/user' \
-H 'Accept: application/json' \
-H 'NS: myapp' \
-H 'DB: main' \
-u 'root:root' \
-d '{"name": "Alice", "email": "alice@example.com", "age": 30}'
# Get a specific record
curl 'http://localhost:8000/key/user/alice' \
-H 'NS: myapp' -H 'DB: main' -u 'root:root'
SurrealQL (The Query Language)
-- Create records (schemaless by default)
CREATE user:alice SET name = 'Alice', email = 'alice@example.com', age = 30;
CREATE user:bob SET name = 'Bob', email = 'bob@example.com', age = 25;
-- Graph relations
RELATE user:alice->follows->user:bob SET since = time::now();
RELATE user:alice->likes->post:intro SET at = time::now();
-- Graph traversal (find friends of friends)
SELECT ->follows->follows->user.name AS friends_of_friends FROM user:alice;
-- Nested queries
SELECT *, ->follows->user.name AS following, <-follows<-user.name AS followers FROM user;
-- Full-text search
SELECT * FROM post WHERE content @@ 'machine learning';
-- Aggregation
SELECT count(), math::mean(age) AS avg_age FROM user GROUP BY country;
-- Live query (real-time)
LIVE SELECT * FROM post WHERE published = true;
JavaScript SDK
import Surreal from 'surrealdb.js';
const db = new Surreal();
await db.connect('http://localhost:8000/rpc');
await db.use({ namespace: 'myapp', database: 'main' });
await db.signin({ username: 'root', password: 'root' });
// Create
const user = await db.create('user', {
name: 'Alice',
email: 'alice@example.com',
tags: ['developer', 'writer']
});
// Query
const adults = await db.query(
'SELECT * FROM user WHERE age > $minAge ORDER BY name',
{ minAge: 18 }
);
// Graph relation
await db.query('RELATE $from->follows->$to', {
from: 'user:alice',
to: 'user:bob'
});
// Live queries
const queryUuid = await db.live('post', (action, result) => {
console.log(`${action}: ${result.title}`);
// CREATE: New Post, UPDATE: Updated Post, DELETE: ...
});
Built-in Auth
-- Define user scope (access control)
DEFINE SCOPE user SESSION 24h
SIGNUP ( CREATE user SET email = $email, pass = crypto::argon2::generate($pass) )
SIGNIN ( SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(pass, $pass) );
-- Define permissions
DEFINE TABLE post SCHEMALESS
PERMISSIONS
FOR select WHERE published = true OR author = $auth.id
FOR create WHERE $auth.id != NONE
FOR update WHERE author = $auth.id
FOR delete WHERE author = $auth.id;
Why SurrealDB
| SurrealDB | PostgreSQL + Redis + Neo4j |
|---|---|
| 1 database | 3 databases |
| Graph + Document + Relational | Pick one model |
| Built-in auth | Add auth layer |
| Real-time built in | Add WebSocket layer |
| Single binary | 3 services to manage |
Need multi-model data collection? Check out my web scraping actors on Apify — structured data from any source.
Need a multi-model database solution? Email me at spinov001@gmail.com.
Top comments (0)