The official SurrealDB SDK for Ruby.
gem install surrealdbOr add to your Gemfile:
gem "surrealdb"require "surrealdb"
SurrealDB.connect("ws://localhost:8000") do |db|
db.signin("user" => "root", "pass" => "root")
db.use("test", "test")
# Create
db.create("person", { "name" => "Alice", "age" => 30 })
# Select
people = db.select("person")
# Query
results = db.query("SELECT * FROM person WHERE age > $min", { "min" => 25 })
# Update
db.merge("person:alice", { "email" => "alice@example.com" })
# Delete
db.delete("person:alice")
endThe SDK supports three transport protocols, selected automatically by URL scheme:
| Scheme | Transport | Live Queries | Sessions | Requires |
|---|---|---|---|---|
ws://, wss:// |
WebSocket | Yes | Yes | -- |
http://, https:// |
HTTP | No | No | -- |
mem://, surrealkv://, file:// |
Embedded | Yes | Yes | surrealdb-embedded gem |
# WebSocket (recommended for most use cases)
client = SurrealDB::Client.new("ws://localhost:8000")
# HTTP (stateless, simpler)
client = SurrealDB::Client.new("http://localhost:8000")
# Embedded (in-process, no server needed)
require "surrealdb/embedded"
client = SurrealDB::Client.new("mem://")SurrealDB.connect("ws://localhost:8000") do |db|
# Root authentication
db.signin("user" => "root", "pass" => "root")
# Namespace authentication
db.signin("user" => "ns_user", "pass" => "ns_pass", "ns" => "my_namespace")
# Database authentication
db.signin("user" => "db_user", "pass" => "db_pass", "ns" => "my_namespace", "db" => "my_database")
# Record user authentication
token = db.signup(
"ns" => "my_namespace",
"db" => "my_database",
"ac" => "user_access",
"username" => "alice",
"password" => "password123"
)
# Token authentication
db.authenticate(token)
# Invalidate session
db.invalidate
endSurrealDB.connect("ws://localhost:8000") do |db|
db.signin("user" => "root", "pass" => "root")
db.use("test", "test")
# Create a record (auto-generated ID)
person = db.create("person", { "name" => "Alice", "age" => 30 })
# Create with specific ID
db.create("person:bob", { "name" => "Bob", "age" => 25 })
# Select all records from a table
people = db.select("person")
# Select a specific record
alice = db.select("person:alice")
# Insert multiple records
db.insert("person", [
{ "name" => "Charlie", "age" => 35 },
{ "name" => "Diana", "age" => 28 }
])
# Update (full replace)
db.update("person:bob", { "name" => "Bob", "age" => 26, "email" => "bob@example.com" })
# Upsert (insert or update)
db.upsert("person:eve", { "name" => "Eve", "age" => 22 })
# Merge (partial update)
db.merge("person:bob", { "email" => "bob@newmail.com" })
# Patch (JSON Patch)
db.patch("person:bob", [
{ "op" => "replace", "path" => "/age", "value" => 27 }
])
# Delete a record
db.delete("person:bob")
# Delete all records from a table
db.delete("person")
# Create a relation
db.relate("person:alice", "knows", "person:bob", { "since" => 2024 })
endSurrealDB.connect("ws://localhost:8000") do |db|
db.signin("user" => "root", "pass" => "root")
db.use("test", "test")
# Simple query
results = db.query("SELECT * FROM person")
# Parameterized query
results = db.query(
"SELECT * FROM person WHERE age > $min_age AND name = $name",
{ "min_age" => 25, "name" => "Alice" }
)
# Multi-statement query
results = db.query(<<~SQL)
CREATE person:alice SET name = 'Alice', age = 30;
CREATE person:bob SET name = 'Bob', age = 25;
SELECT * FROM person;
SQL
# Connection-scoped variables
db.set("current_user", "alice")
results = db.query("SELECT * FROM person WHERE name = $current_user")
db.unset("current_user")
# Run a SurrealDB function
result = db.run("fn::my_function", "arg1", "arg2")
endUse query_raw to get per-statement metadata (status, timing, errors) for multi-statement queries:
results = db.query_raw("CREATE person:a SET name = 'Alice'; SELECT * FROM missing_table;")
results.each do |qr|
if qr.ok?
puts "#{qr.time}: #{qr.result}"
else
puts "Error: #{qr.error}"
end
endFor in-process usage without a separate server, install the embedded gem:
gem install surrealdb-embeddedThen opt in with an extra require:
require "surrealdb"
require "surrealdb/embedded"
SurrealDB.connect("mem://") do |db|
db.use("test", "test")
db.create("person", { "name" => "Alice" })
endSupported schemes: mem:// (in-memory), surrealkv://path (persistent), file://path (file-based).
Requires libsurrealdb_c installed on the system or pointed to via SURREALDB_LIB_PATH.
Enable automatic WebSocket reconnection with exponential backoff:
client = SurrealDB::Client.new("ws://localhost:8000",
reconnect: true,
reconnect_max_retries: 5,
reconnect_delay: 1.0
)
client.connect
client.signin("user" => "root", "pass" => "root")
client.use("test", "test")
# If the connection drops, the SDK will automatically reconnect,
# replay use/signin/let state, and retry the failed request.
client.query("SELECT * FROM person")Live queries are supported over WebSocket and embedded connections.
SurrealDB.connect("ws://localhost:8000") do |db|
db.signin("user" => "root", "pass" => "root")
db.use("test", "test")
# Start a live query
live_id = db.live("person")
# Subscribe to notifications
db.subscribe(live_id) do |notification|
puts "Action: #{notification['action']}"
puts "Result: #{notification['result']}"
end
# Changes to the table will trigger notifications
db.create("person", { "name" => "Alice" })
# Stop the live query
db.kill(live_id)
endThe SDK provides Ruby types that map to SurrealDB's type system:
# RecordID
rid = SurrealDB::RecordID.new("person", "alice")
rid = SurrealDB::RecordID.parse("person:alice")
rid.table # => "person"
rid.id # => "alice"
# Table
table = SurrealDB::Table.new("person")
# Duration
duration = SurrealDB::Duration.parse("1h30m")
duration.secs # => 5400
duration.to_f # => 5400.0
# None (distinct from nil/NULL)
SurrealDB::NONE
# Geometry
point = SurrealDB::GeometryPoint.new(-122.4194, 37.7749)
line = SurrealDB::GeometryLine.new(point1, point2)
polygon = SurrealDB::GeometryPolygon.new(exterior_ring)
# Range
range = SurrealDB::Range.new(
SurrealDB::BoundIncluded.new(1),
SurrealDB::BoundExcluded.new(10)
)begin
db.query("INVALID SYNTAX")
rescue SurrealDB::QueryError => e
puts "Query failed: #{e.message}"
rescue SurrealDB::NotFoundError => e
puts "Not found: #{e.message}"
rescue SurrealDB::NotAllowedError => e
puts "Permission denied: #{e.message}"
rescue SurrealDB::ServerError => e
# Catch-all for server errors
puts "Server error (#{e.kind}): #{e.message}"
puts "Cause: #{e.server_cause.message}" if e.server_cause
rescue SurrealDB::ConnectionError => e
puts "Connection lost: #{e.message}"
rescue SurrealDB::TimeoutError => e
puts "Request timed out: #{e.message}"
endSurrealDB.configure do |config|
config.timeout = 60 # seconds (default: 30)
config.logger = Logger.new($stdout)
end
# Per-connection timeout
client = SurrealDB::Client.new("ws://localhost:8000", timeout: 10)- Fork the repository
- Create your feature branch (
git checkout -b feature/my-feature) - Run the tests (
bundle exec rspec) - Run the linter (
bundle exec rubocop) - Commit your changes
- Push to the branch
- Create a Pull Request
Integration tests require a running SurrealDB instance:
docker run --rm -p 8000:8000 surrealdb/surrealdb:latest start --user root --pass root --allow-all
bundle exec rspec spec/integration