| Crates.io | rustmemodb |
| lib.rs | rustmemodb |
| version | 0.1.2 |
| created_at | 2026-01-09 07:07:06.320969+00 |
| updated_at | 2026-01-14 06:00:44.070061+00 |
| description | In-memory SQL database with transaction support, connection pooling, and MVCC |
| homepage | https://github.com/maxBogovick/rustmemodb |
| repository | https://github.com/maxBogovick/rustmemodb |
| max_upload_size | |
| id | 2031713 |
| size | 1,334,239 |
The logic-first, in-memory SQL engine designed for high-performance testing and rapid prototyping.
"Postgres is for production. SQLite is for files. RustMemDB is for code."
Integration testing in Rust usually forces a painful tradeoff:
RustMemDB is the Third Way.
It is a pure Rust SQL engine with MVCC and Snapshot Isolation that introduces a paradigm shift in testing: Instant Database Forking.
| Feature | RustMemDB 🦀 | SQLite :floppy_disk: | Docker (Postgres) 🐳 |
|---|---|---|---|
| Startup Time | < 1ms | ~10ms | 1s - 5s |
| Test Isolation | Instant Fork (O(1)) | File Copy / Rollback | New Container / Truncate |
| Parallelism | ✅ Safe & Fast | ❌ Locking Issues | ⚠️ High RAM Usage |
| Type Safety | ✅ Strict | ❌ Loose / Dynamic | ✅ Strict |
| Dependencies | Zero (Pure Rust) | C Bindings | Docker Daemon |
Stop seeding your database for every test function.
RustMemDB uses Persistent Data Structures (Copy-On-Write) via the im crate to clone the entire database state instantly.
The "Seed Once, Test Anywhere" Workflow:
Step 1: Setup (Runs once)
[ Master DB ] <--- Create Tables, Insert 50k Seed Rows (Heavy)
|
+------------------------+------------------------+
| (Microseconds) | (Microseconds) |
▼ ▼ ▼
[ Fork: Test A ] [ Fork: Test B ] [ Fork: Test C ]
Delete ID=1 Update ID=2 Select Count(*)
(Isolated Change) (Isolated Change) (Sees Original Data)
use rustmemodb::Client;
#[tokio::test]
async fn test_parallel_logic() -> anyhow::Result<()> {
// 1. Heavy Initialization (Done once per suite)
let master = Client::connect_local("admin", "pass").await?;
master.execute("CREATE TABLE users (id INT, name TEXT)").await?;
// ... imagine inserting 10,000 rows here ...
// 2. Create an O(1) Fork for this specific test
let db = master.fork().await?;
// 3. Mutate safely. Master and other tests are unaffected.
db.execute("DELETE FROM users").await?;
assert_eq!(db.query("SELECT count(*) FROM users").await?.row_count(), 0);
Ok(())
}
Time taken to create an isolated database environment ready for a test:
RustMemDB (Forking): [=] < 1ms 🚀
SQLite (In-Memory): [==] 10ms
Docker (Postgres): [==================================================] 2500ms+
RustMemDB is approximately 2500x faster than spinning up a Docker container for isolation.
We support a rich subset of SQL-92, focusing on the features most used in application logic.
| Category | Supported Features |
|---|---|
| Data Types | INTEGER (i64), FLOAT (f64), TEXT, BOOLEAN, NULL |
| Operators | +, -, *, /, % |
| Comparisons | =, !=, <, >, <=, >= |
| Logic | AND, OR, NOT, Parentheses ( ) |
| Predicates | LIKE (Pattern matching), BETWEEN, IS NULL, IS NOT NULL, IN (list) |
| Aggregates | COUNT(*), SUM(col), AVG(col), MIN(col), MAX(col) |
| Constraints | PRIMARY KEY (Unique + Not Null), UNIQUE |
| Statements | CREATE/DROP TABLE, CREATE INDEX, INSERT, UPDATE, DELETE, SELECT |
| Clauses | WHERE, ORDER BY (Multi-column), LIMIT |
| Transactions | BEGIN, COMMIT, ROLLBACK |
RustMemDB is built for Rust developers. Expanding the database with custom functions is trivial compared to C-based databases (SQLite/Postgres).
Goal: Add a custom SCRAMBLE(text) function.
use rustmemodb::core::{Value, Result};
use rustmemodb::evaluator::ExpressionEvaluator;
struct ScrambleFn;
impl ExpressionEvaluator for ScrambleFn {
fn evaluate(&self, args: &[Value]) -> Result<Value> {
let text = args[0].as_str().unwrap();
let scrambled: String = text.chars().rev().collect();
Ok(Value::Text(scrambled))
}
}
// Register and use immediately
db.register_function("SCRAMBLE", Box::new(ScrambleFn));
let result = db.query("SELECT SCRAMBLE('hello')"); // Returns 'olleh'
We believe databases should be a joy to use, not a black box.
No C compilers, no libsqlite3-dev dependencies, no FFI overhead. RustMemDB is async from the ground up, built on tokio.
Stop guessing why your query failed.
Error: TypeMismatch
=> Column 'age' expects INTEGER, got TEXT ('twenty')
Unlike SQLite, RustMemDB enforces types. If you define an INTEGER column, you cannot insert a string. This catches bugs in your application logic before they hit production.
RustMemDB isn't trying to replace PostgreSQL in production. It excels where others fail:
Run 1000s of integration tests in parallel without managing Docker containers or worrying about port conflicts.
Drafting a schema or an API? Don't waste time setting up docker-compose.yml. Just cargo run and you have a SQL engine.
Need to query internal application state using SQL? Use RustMemDB as an embedded library to store configuration or session data.
SELECT * FROM sessions WHERE inactive > 1h.Built on Rust's guarantees.
unsafe blocks in core logic. Immune to buffer overflows and use-after-free bugs that plague C-based databases.RustMemDB provides a standardized DatabaseClient trait. Write your business logic once, and run it against RustMemDB in tests and Postgres in production.
Your Service:
use rustmemodb::{DatabaseClient, Result};
pub struct UserService<D: DatabaseClient> {
db: D
}
impl<D: DatabaseClient> UserService<D> {
pub async fn create(&self, name: &str) -> Result<()> {
self.db.execute(&format!("INSERT INTO users (name) VALUES ('{}')", name)).await?;
Ok(())
}
}
Production (main.rs):
// Wrapper for tokio-postgres
let pg_client = PostgresAdapter::connect("postgres://...").await?;
let service = UserService::new(pg_client);
Testing (tests.rs):
// Works instantly!
let mem_client = rustmemodb::Client::connect_local("admin", "pass").await?;
let service = UserService::new(mem_client);
"In-memory" doesn't mean "data loss". RustMemDB supports full persistence via Write-Ahead Logging (WAL).
use rustmemodb::{InMemoryDB, DurabilityMode};
async fn persistence_example() -> anyhow::Result<()> {
let mut db = InMemoryDB::new();
// Enable WAL persistence to ./data directory
db.enable_persistence("./data", DurabilityMode::Wal).await?;
// Changes are now fsync'd to disk
db.execute("INSERT INTO important_data VALUES (1)")?;
// On restart, just call enable_persistence again to recover!
Ok(())
}
RustMemDB is written in Rust, for Rust developers. It exposes a powerful Plugin API. Want to add a custom function? You don't need C-extensions.
// Define a custom evaluator
struct UpperEvaluator;
impl ExpressionEvaluator for UpperEvaluator {
fn evaluate(&self, args: &[Value]) -> Result<Value> {
match &args[0] {
Value::Text(s) => Ok(Value::Text(s.to_uppercase())),
_ => Err(DbError::TypeMismatch("Expected text".into()))
}
}
}
// Register it
db.register_function("UPPER", Box::new(UpperEvaluator));
// Use it immediately
db.query("SELECT UPPER(name) FROM users");
We take engineering seriously. This is not just a Vec<Row>.
im-rs for O(1) cloning and efficient memory usage.PRIMARY KEY and UNIQUE constraints.O(log n), not O(n).Arc and Copy-On-Write, eliminating read contention on the catalog.Q: Can I use this in production? A: Use Postgres or MySQL for critical production data storage. Use RustMemDB for testing, prototyping, or embedded scenarios where Postgres is overkill.
Q: Is it faster than HashMap?
A: No. A HashMap is O(1). A SQL engine handles Parsing, Planning, and Transactions. Use RustMemDB when you need Relational Logic (Joins, Where clauses, transactions), not just Key-Value storage.
Q: Does it support the Postgres Wire Protocol? A: Not yet (Planned). Currently, you use it via the Rust library API.
Add this to your Cargo.toml:
[dependencies]
rustmemodb = "0.1.2"
We are building the best testing database for the Rust ecosystem.
MIT. Use it freely in your OSS or commercial projects.
Built with ❤️ in Rust