RubyDB is a Ruby-native relational database with an embedded engine, a client/server mode, a Ruby client, and an ActiveRecord adapter.
Author: Aldane Hutchinson
Status: alpha. RubyDB is suitable for experimentation, development, controlled embedded workloads, and production microservices that stay within the documented and tested feature set. RubyDB can be used in both development and production, but each production workload must pass its own query, concurrency, backup, restore, security, and operational validation. It provides a tested common SQLite-style profile, but is not a drop-in replacement for PostgreSQL, MySQL, or SQLite.
Use RubyDB when you want a Ruby-native database for local development, tests, internal tools, or an independently owned microservice with a bounded workload. Use embedded mode when one Ruby process owns the database file. Use RubyDB server/client mode when multiple application processes connect to one service.
Use PostgreSQL as the default system of record for massive applications, high-concurrency public products, large shared Rails applications, advanced PostgreSQL SQL/extensions, and workloads requiring a mature managed database ecosystem. A common production architecture is PostgreSQL for the main app and RubyDB for smaller, independently operated microservices.
RubyDB's ecosystem is built around a clear boundary: application code connects
to a RubyDB server through the documented client/server protocol. The embedded
.rdb file format is an internal storage implementation, not a public API for
third-party drivers. This lets RubyDB evolve its storage safely while language
and framework communities build clients that share the same server behavior.
Official integration surfaces include:
- Ruby's direct API and the
rubydbclient/server client rubydb-activerecordfor Rails applicationsrubydb-pythonfor Python DB-API 2.0 applicationsrubydb-nodefor Node.js and TypeScript applications- Sequel and other Ruby integrations documented under
adapters/
Community developers can create adapters for another language, framework, ORM, query builder, migration tool, observability system, or job framework. Every adapter should begin with the server protocol and the executable protocol tests, then provide an idiomatic API for its community. A production adapter must preserve parameter binding, transaction ownership, deadlines and wire cancellation, TLS verification, bounded frames, error details, and clean connection shutdown. A wrapper that only sends a string of SQL is not a production adapter.
Use a distinct package name such as rubydb-go, rubydb-django, or
@your-scope/rubydb and make its ownership clear. Do not present a community
package as an official RubyDB release. Add the adapter to the ecosystem list
only after it has live integration tests against a real RubyDB server and its
supported RubyDB versions are documented. The complete build, test, security,
and publishing workflow is in
Lesson 11: Build a community adapter.
The repository contains implementation and automated coverage for:
- SQL tables, CRUD, joins, grouping and aggregates, ordering, transactions, savepoints, conflict handling, and documented maintenance statements
- typed values, primary/foreign keys, unique and check constraints, and B-tree indexes
- durable storage, WAL-backed commits, recovery, snapshots, branching, and MVCC paths
- Ruby API, client/server protocol, connection pooling, configuration, and operational tooling
- ActiveRecord integration, Rails migrations, and a runnable Rails example
These features are not a guarantee of compatibility with every application. Run the test suite and validate your own schema, queries, workload, backup, restore, and failure scenarios before using RubyDB for important data.
That requirement is only necessary when RubyDB is intended to be a drop-in replacement for an existing application using one of those databases.
It includes much more than accepting similar SELECT statements:
- dialect-specific SQL syntax, functions, operators, casts, and error behavior
- query semantics for joins,
NULL, ordering, grouping, subqueries, CTEs, unions, upserts, and window functions - data types, indexes, constraints, generated values, and transaction behavior
- migration behavior and ActiveRecord adapter mappings
- client protocol, connection behavior, locking, limits, and operational tools
A new Ruby or Rails application does not need complete compatibility. It can use RubyDB's documented SQL and adapter behavior directly. Compatibility is needed to move an existing PostgreSQL, MySQL, or SQLite application without rewriting queries and without discovering semantic differences in production.
RubyDB currently targets a documented RubyDB SQL subset plus tested Rails operations. The compatibility documents describe the supported statements; unsupported or unverified dialect features must not be assumed to work.
Install the release gem:
gem install rubydb For local development from this repository:
bundle install
bundle exec rspecRubyDB can run embedded in a single owning process:
require "rubydb"
engine = RubyDB::Storage::Engine.new("tmp/example.rdb")
engine.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
engine.execute("INSERT INTO users (name) VALUES ('Aldane')")
puts engine.execute("SELECT * FROM users").inspect
engine.closeFor multiple application processes, use RubyDB's server/client mode and point clients at the managed server. Do not open the same embedded database path from multiple independent processes. A regular Ruby application can use a RubyDB connection URL supplied by its environment:
client = RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL"))
client.query("SELECT 1")
client.disconnectUse the rubydb:// or TLS-enabled rubydbs:// format documented in the Rails
configuration guide. RubyDB URLs are not PostgreSQL URLs.
This creates a durable local database in one owning Ruby process:
require "rubydb"
engine = RubyDB::Storage::Engine.new("tmp/development.rdb")
begin
engine.execute("CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT NOT NULL)")
engine.execute("INSERT INTO notes (body) VALUES ('First note')")
puts engine.execute("SELECT id, body FROM notes ORDER BY id").inspect
ensure
engine.close
endDo not open the same embedded path from separate web and worker processes.
Run one RubyDB server on persistent storage and inject a TLS URL into the service:
gem install rubydb -v 0.1.5
rubydb --config /etc/rubydb/production.yml --env production startrequire "rubydb"
client = RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL"))
begin
puts client.query("SELECT 1").to_hash
ensure
client.disconnect
endUse a URL such as rubydbs://user:URL_ENCODED_PASSWORD@db.internal:7432/app
with TLS verification enabled. Store the complete URL in a secret manager and
keep the database service on a private network.
Use the pg gem and a managed PostgreSQL connection string for the main
application:
# Gemfile
gem "pg"# config/database.yml
production:
url: <%= ENV.fetch("DATABASE_URL") %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>Set DATABASE_URL through the hosting provider’s secret settings, run
migrations once from a release job, and validate the application against the
same PostgreSQL major version used in production.
The small Rails 7.2 application in
examples/rails_app runs a real migration, model query,
and browser form through rubydb-activerecord.
cd examples/rails_app
bundle install
bundle exec ruby bin/rails db:migrate
bundle exec ruby bin/rails server -b 127.0.0.1 -p 3001Open http://127.0.0.1:3001/. The example uses an embedded database under
tmp/; set RUBYDB_DATABASE to choose another path. See the adapter and Rails
documentation for network configuration, migrations, production deployment,
backups, restore drills, and monitoring.
For an even smaller end-to-end smoke test, see the tiny GitHub-style app in
examples/github_clone. It covers repositories,
issues, commits, Rails associations, foreign keys, indexes, seed data, and a
browser page backed by RubyDB.
RubyDB does not claim complete PostgreSQL, MySQL, or SQLite compatibility until each compatibility area has both an implementation and repeatable validation. The project must validate at least:
- parser and execution behavior for the documented dialect surface
- type, constraint, transaction, locking, and error semantics
- ActiveRecord queries, joins, eager loading, associations, and migrations
- sustained concurrency, cancellation, recovery, backup/restore, and failover
- supported Ruby, Rails, operating-system, and client/server combinations
Until then, compatibility should be treated as feature-specific, not implied by the presence of an adapter.
- Documentation index
- Production journey
- Developer guide
- Troubleshooting guide
- Debugging playbook
- Production operations guide
- Lessons learned
- Getting started
- Local development to production
- SQL compatibility
- SQL compatibility guide
- SQLite compatibility profile
- SQL syntax
- Rails installation
- Rails production guidance
- Rails compatibility guide
- Python adapter
- Production readiness
- Operations and workload testing
- Production runbook
- CLI guide
- CLI cheat sheet
- Release checklist
- Security policy
- Contributing and testing
- Roadmap
RubyDB is released under the MIT License.