A MongoDB-compatible server powered by EasyDB. Connect with any standard MongoDB client and store data on your choice of backend.
mongosh ──┐
pymongo ──┤ ┌─────────┐
├── TCP:27017 ─│ EasyDB │── SQLite
Compass ──┤ │ Server │── PostgreSQL
├──────────────│ │── Memory
mongoose ─┘ └─────────┘── Redis, MySQL, Turso...
FerretDB gives you MongoDB compatibility on PostgreSQL. EasyDB Server gives you MongoDB compatibility on any backend — SQLite, PostgreSQL, MySQL, Redis, in-memory, and more. One server, 10+ storage engines.
This project serves as a real-world showcase of EasyDB's universal storage abstraction.
# Run with in-memory storage (no persistence)
npx @rckflr/easydb-server
# Run with SQLite (persistent)
npx @rckflr/easydb-server --adapter sqlite --data ./mydata
# Then connect with mongosh
mongosh mongodb://localhost:27017// Or connect with the Node.js driver
import { MongoClient } from 'mongodb';
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const db = client.db('test');
await db.collection('users').insertOne({ name: 'Alice', age: 30 });
const user = await db.collection('users').findOne({ name: 'Alice' });
console.log(user); // { _id: ObjectId('...'), name: 'Alice', age: 30 }npm install -g @rckflr/easydb-server
# SQLite support (recommended for persistent storage)
npm install -g @rckflr/easydb-server better-sqlite3
# PostgreSQL support
npm install -g @rckflr/easydb-server pgeasydb-server [options]
Options:
--port, -p <port> Port to listen on (default: 27017)
--host <host> Host to bind to (default: 0.0.0.0)
--adapter, -a <name> Storage backend (default: memory)
--data, -d <path> Data directory (for sqlite)
--connection-string <url> Database URL (for postgres)
--debug Enable debug logging
--quiet Only show warnings and errors
--help Show help# In-memory (great for testing)
easydb-server
# SQLite with persistent storage
easydb-server --adapter sqlite --data ./data
# SQLite on a custom port
easydb-server -a sqlite -d ./data -p 27018
# PostgreSQL
easydb-server --adapter postgres --connection-string "postgresql://user:pass@localhost:5432/mydb"
# Debug mode (see every command)
easydb-server --adapter sqlite --data ./data --debug| Backend | Flag | Persistence | Best For |
|---|---|---|---|
| Memory | --adapter memory |
No | Testing, development, CI |
| SQLite | --adapter sqlite --data ./path |
Yes | Single-server, embedded, edge |
| PostgreSQL | --adapter postgres --connection-string "..." |
Yes | Production, multi-tenant |
All backends are powered by EasyDB adapters and can be swapped with a single CLI flag — your application code doesn't change.
Data is stored in per-collection .sqlite files:
./data/
├── _easydb_meta___global.sqlite # Collection registry
├── test.users.sqlite # db.users collection
├── test.products.sqlite # db.products collection
└── myapp.orders.sqlite # myapp.orders collection
Collections are automatically restored on server restart.
| Operation | Status | Examples |
|---|---|---|
| insertOne / insertMany | Full | db.users.insertOne({name: "Alice"}) |
| find / findOne | Full | db.users.find({age: {$gt: 25}}) |
| updateOne / updateMany | Full | db.users.updateOne({name: "Alice"}, {$set: {age: 31}}) |
| deleteOne / deleteMany | Full | db.users.deleteOne({name: "Alice"}) |
| countDocuments | Full | db.users.countDocuments({role: "admin"}) |
| distinct | Full | db.users.distinct("role") |
| findOneAndUpdate | Full | db.users.findOneAndUpdate(filter, update, {returnDocument: "after"}) |
| findOneAndDelete | Full | db.users.findOneAndDelete({name: "Alice"}) |
| sort / skip / limit | Full | db.users.find().sort({age: -1}).skip(10).limit(5) |
| projection | Full | db.users.find({}, {name: 1, email: 1}) |
| aggregate | Basic | $match, $sort, $limit, $skip, $project, $group, $count, $unwind, $set |
| createIndex | Stub | Acknowledged but not enforced |
| show dbs / collections | Full | show dbs, show collections |
| drop / dropDatabase | Full | db.users.drop(), db.dropDatabase() |
| Category | Operators |
|---|---|
| Comparison | $eq $ne $gt $gte $lt $lte $in $nin |
| Logical | $and $or $not $nor |
| Element | $exists $type |
| Array | $size $all $elemMatch |
| Evaluation | $regex $mod |
| Implicit | {field: value} (exact match, works with arrays) |
| Operator | Description |
|---|---|
$set |
Set field value |
$unset |
Remove field |
$inc |
Increment number |
$mul |
Multiply number |
$min / $max |
Set if less/greater than current |
$push |
Append to array (supports $each) |
$pull |
Remove from array |
$addToSet |
Append unique to array |
$pop |
Remove first/last from array |
$rename |
Rename field |
$currentDate |
Set to current date |
| Stage | Status |
|---|---|
$match |
Full |
$sort |
Full |
$skip / $limit |
Full |
$project |
Full |
$count |
Full |
$group |
$sum, $avg, $min, $max, $push, $addToSet, $first, $last |
$unwind |
Full |
$set / $addFields |
Basic (field references only) |
$lookup |
Not supported |
$facet |
Not supported |
These MongoDB features are intentionally out of scope:
- Transactions (multi-document)
- Change streams
- Aggregation:
$lookup,$facet,$bucket,$graphLookup - Full-text search (
$text) - Geospatial queries
- Authentication (SCRAM-SHA-256)
- Replication / Sharding
- GridFS
- Wire compression
┌─────────────────────────────────────────┐
│ MongoDB Client │
└──────────────┬──────────────────────────┘
│ TCP (MongoDB Wire Protocol)
│ OP_MSG + OP_QUERY (BSON)
▼
┌─────────────────────────────────────────┐
│ EasyDB Server │
│ │
│ Wire Protocol ─→ Command Router │
│ │ │
│ ┌───────┼────────┐ │
│ ▼ ▼ ▼ │
│ Handshake CRUD Admin │
│ │ │
│ Query Engine │
│ (matcher + updater) │
│ │ │
│ DatabaseManager │
│ │ │
│ EasyDB Core │
│ .put() .get() .where() │
└──────────────┬──────────────────────────┘
│
┌───────┼───────┐
▼ ▼ ▼
SQLite Postgres Memory ...
- Development: Drop-in MongoDB replacement that requires zero setup
- Testing: Ephemeral in-memory database for CI/CD pipelines
- Edge/Embedded: Run a MongoDB-compatible database on devices with SQLite
- Prototyping: Start with SQLite, switch to PostgreSQL for production
- Learning: Understand how MongoDB wire protocol works under the hood
# Build
docker build -t easydb-server .
# Run with in-memory
docker run -p 27017:27017 easydb-server
# Run with SQLite persistence
docker run -p 27017:27017 -v ./data:/data easydb-server \
--adapter sqlite --data /dataOr with docker-compose:
services:
easydb:
build: .
ports:
- "27017:27017"
volumes:
- ./data:/data
command: ["--adapter", "sqlite", "--data", "/data"]| Feature | EasyDB Server | FerretDB | MongoDB |
|---|---|---|---|
| Storage backends | 10+ | 2 | 1 |
| SQLite backend | Yes | Yes | No |
| PostgreSQL backend | Yes | Yes | No |
| MySQL/Redis/KV backend | Yes | No | No |
| In-memory mode | Yes | No | No |
| Zero config startup | Yes | No | Yes |
| npm installable | Yes | No | No |
| Docker image size | ~50MB | ~100MB | ~700MB |
| CRUD operations | Full | Full | Full |
| Aggregation | Basic | Most | Full |
| Transactions | No | Partial | Full |
| Auth/TLS | No | Yes | Full |
| License | MIT | Apache 2.0 | SSPL |
PRs welcome! See SPEC.md for the full technical specification.
MIT