Back to Articles

SurrealDB: The Database That Wants to Replace Your Backend

[ View on GitHub ]

SurrealDB: The Database That Wants to Replace Your Backend

Hook

What if your frontend could query a graph database directly, with row-level permissions enforced at the database layer, eliminating your entire Express.js API? That’s the premise of SurrealDB.

Context

Modern applications typically juggle multiple databases: PostgreSQL for relational data, MongoDB for documents, Neo4j for relationships, Redis for caching, and perhaps Elasticsearch for search. Each database requires its own client library, migration strategy, and operational expertise. Then you build an API server—often in Node.js or Go—to orchestrate these databases, implement authentication, enforce permissions, and expose REST or GraphQL endpoints. This architecture works, but it’s heavy.

SurrealDB emerged from a different question: what if the database itself could handle multiple data models, enforce granular permissions, and speak directly to clients over WebSockets? Written in Rust and designed for the “realtime web,” it attempts to collapse the traditional three-tier architecture (database → API server → client) into two tiers by embedding backend logic directly into the database layer. It’s not the first to try this—Firebase and Parse pioneered the backend-as-a-service model—but SurrealDB is unique in its ambition to be both a proper database (with ACID transactions and a SQL-like query language) and a complete backend platform.

Technical Insight

SurrealDB Core

ws://connect + signin

validate scope

authenticated context

SurrealQL query

parsed AST

apply WHERE $auth rules

read/write records

live query updates

real-time events

Browser Client

SurrealDB.js

WebSocket/RPC

Endpoint

Authentication

Scope Engine

SurrealQL

Query Parser

Permission

Evaluator

Multi-Model

Storage Engine

Unified Record

Storage

System architecture — auto-generated

At its core, SurrealDB implements what it calls a “multi-model” approach through a unified data structure: everything is stored as records with unique IDs, but these records can relate to each other as graph edges, be queried as documents, or filtered relationally. The query language, SurrealQL, extends SQL syntax to handle all these paradigms. Here’s what connecting directly from a browser looks like:

import Surreal from 'surrealdb.js';

const db = new Surreal();
await db.connect('ws://localhost:8000/rpc');

// Authenticate as an end-user (not a database admin)
await db.signin({
  NS: 'myapp',
  DB: 'production',
  SC: 'user_scope', // Scope defines permission rules
  email: 'user@example.com',
  pass: 'password123'
});

// Query with graph traversal and filtering
const posts = await db.query(`
  SELECT *, author.*, ->likes->user AS liked_by
  FROM post
  WHERE author.country = 'US'
    AND created_at > time::now() - 7d
  FETCH author, liked_by
`);

// Subscribe to real-time changes
const unsubscribe = await db.live('post', (action, result) => {
  console.log(action, result); // 'CREATE', 'UPDATE', 'DELETE'
});

This code runs in the browser without an intermediary API server. The SC: 'user_scope' parameter is crucial—it tells SurrealDB to apply a specific permission schema defined in the database. Here’s how you’d define that schema:

DEFINE SCOPE user_scope
  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 TABLE post SCHEMALESS
  PERMISSIONS
    FOR select WHERE published = true OR author = $auth.id
    FOR create WHERE $auth.id != NONE
    FOR update, delete WHERE author = $auth.id;

DEFINE FIELD author ON TABLE post TYPE record<user>
  VALUE $auth.id;
DEFINE FIELD created_at ON TABLE post TYPE datetime
  VALUE time::now();

The PERMISSIONS clause is enforced at query execution time. When the authenticated user runs SELECT * FROM post, SurrealDB automatically appends WHERE published = true OR author = $auth.id to the query. The VALUE clause on the author field means you can’t forge authorship—it’s always set to the authenticated user’s ID. This is authorization logic traditionally written in application code, now declarative and database-enforced.

The graph capabilities shine in relational queries. SurrealDB uses -> for outbound edges and <- for inbound:

-- Create records and relationships
CREATE user:alice SET name = 'Alice';
CREATE user:bob SET name = 'Bob';
RELATE user:alice->follows->user:bob;

-- Find followers of followers (2 hops)
SELECT name, ->follows->user->follows->user.name AS fof
FROM user:alice;

-- Bidirectional traversal: who follows Alice?
SELECT <-follows<-user.name AS followers FROM user:alice;

Under the hood, SurrealDB supports multiple storage engines. The default is RocksDB (file-based), but you can plug in TiKV for distributed deployments or even run entirely in memory. The storage layer is abstracted behind a key-value interface, and the query engine operates on this abstraction. This allows the same database binary to run embedded in an application, as a single server, or as a distributed cluster—the API surface remains identical.

The Rust implementation provides memory safety and performance, but more interestingly, it compiles to WebAssembly. This means you can run SurrealDB entirely in the browser with an IndexedDB backend, useful for offline-first applications that sync when connected. The query language stays the same whether you’re querying a local WASM instance or a remote cluster.

Gotcha

The licensing model is the elephant in the room. SurrealDB uses the Business Source License 1.1, which means you can use it freely for non-production or internal production use, but commercial SaaS offerings or selling products built on SurrealDB require a commercial license for four years. After that, each version converts to Apache 2.0. For bootstrapped startups, this is likely fine. For enterprises with strict open-source policies or companies planning to offer database-as-a-service products, it’s a non-starter. You can’t just fork it and offer “Managed SurrealDB” without negotiating with SurrealDB Ltd.

The bigger architectural concern is whether consolidating so many responsibilities into the database is wise. The permission system, while powerful, means your authorization logic is now in database schema definitions rather than application code. This is harder to version control (schema changes require migrations), harder to test (you need a running database to validate permission rules), and harder to debug when something goes wrong. The real-time subscription system can create resource pressure—thousands of concurrent WebSocket connections all running live queries is a very different load profile than traditional request-response patterns. And while SurrealQL is more expressive than SQL, it’s also another query language to learn. For teams already invested in PostgreSQL expertise, the learning curve is real. The ecosystem is young: you won’t find the mature ORMs, admin tools, monitoring solutions, or hosted providers that more established databases enjoy.

Verdict

Use if: You’re building a real-time application (collaborative tools, live dashboards, chat systems) where multiple data models coexist—documents for user profiles, graphs for social connections, time-series for activity logs—and you want to reduce infrastructure complexity by eliminating the API server layer. It’s particularly compelling for small teams, prototypes, or edge computing scenarios where deploying and maintaining separate databases isn’t practical. The direct-to-database model works brilliantly for applications where the frontend team can own more of the stack with declarative permissions providing safety rails. Skip if: You need a battle-tested database for high-stakes production workloads where five-nines uptime matters more than developer convenience, require a fully open-source license without commercial restrictions, or have deep expertise in specialized databases that SurrealDB is trying to replace—Postgres with proper extensions, Neo4j for complex graph algorithms, or TimescaleDB for time-series analytics will outperform SurrealDB’s generalist approach. Also skip if your team has significant investment in existing ORMs and database tooling that won’t translate to SurrealQL.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/data-knowledge/surrealdb-surrealdb.svg)](https://starlog.is/api/badge-click/data-knowledge/surrealdb-surrealdb)