FerretDB on a VPS: MongoDB-Compatible Database on PostgreSQL Without MongoDB Licensing
FerretDB is an open-source proxy that translates MongoDB wire protocol queries into PostgreSQL — giving you MongoDB API compatibility backed by PostgreSQL’s proven storage engine. After MongoDB changed its license to SSPL in 2018, many teams sought alternatives. FerretDB lets you keep MongoDB client libraries and query syntax while running on open-source PostgreSQL. It’s ideal for teams using MongoDB for simple document storage who want SSPL-free infrastructure.
FerretDB vs MongoDB vs DocumentDB
- FerretDB: Open-source (Apache 2.0), MongoDB API compatibility, PostgreSQL backend, no SSPL concerns, limited aggregation support
- MongoDB Community: SSPL license, full feature set, best performance for complex queries
- AWS DocumentDB: MongoDB-compatible, managed, expensive, AWS lock-in
- Choose FerretDB: Applications using basic MongoDB CRUD and simple aggregations, teams that want PostgreSQL as the actual storage layer for operational familiarity
Step 1: Docker Compose Setup
<code">mkdir -p /opt/ferretdb && cd /opt/ferretdb nano docker-compose.yml
<code">version: '3.8'
services:
ferretdb:
image: ghcr.io/ferretdb/ferretdb:latest
container_name: ferretdb
restart: always
ports:
- "127.0.0.1:27017:27017" # MongoDB wire protocol port
environment:
FERRETDB_POSTGRESQL_URL: postgres://ferretdb:${POSTGRES_PASSWORD}@ferretdb-db/ferretdb
depends_on:
ferretdb-db:
condition: service_healthy
ferretdb-db:
image: postgres:16-alpine
container_name: ferretdb-postgres
restart: always
environment:
POSTGRES_DB: ferretdb
POSTGRES_USER: ferretdb
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ferretdb_db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ferretdb"]
interval: 10s
timeout: 5s
retries: 5
volumes:
ferretdb_db:
<code">echo "POSTGRES_PASSWORD=StrongFerretDbPassword!" > .env chmod 600 .env docker compose up -d docker compose logs -f ferretdb
Step 2: Connect with MongoDB Tools
<code"># Connect with mongosh (MongoDB shell)
mongosh "mongodb://localhost:27017/mydb"
# FerretDB requires username/password (default: ferretdb/ferretdb for dev)
mongosh "mongodb://username:password@localhost:27017/mydb?authMechanism=PLAIN"
# Connection string format for applications:
# mongodb://username:password@localhost:27017/database?authMechanism=PLAIN
# Verify FerretDB is responding:
mongosh --eval 'db.adminCommand({ serverStatus: 1 })' | head -20
Step 3: Create Database and Collections
<code">mongosh "mongodb://localhost:27017/mydb"
<code"># MongoDB shell — identical syntax to MongoDB
use mydb
// Create collection and insert documents
db.users.insertMany([
{ name: "Alice", email: "alice@example.com", age: 30, tags: ["admin", "user"] },
{ name: "Bob", email: "bob@example.com", age: 25, tags: ["user"] },
{ name: "Charlie", email: "charlie@example.com", age: 35, tags: ["user", "premium"] }
])
// Create indexes
db.users.createIndex({ email: 1 }, { unique: true })
db.users.createIndex({ tags: 1 })
// Query
db.users.find({ age: { $gte: 30 } })
db.users.findOne({ email: "alice@example.com" })
// Update
db.users.updateOne(
{ name: "Alice" },
{ $set: { role: "superadmin" }, $addToSet: { tags: "moderator" } }
)
// Delete
db.users.deleteOne({ name: "Charlie" })
Step 4: Python Application Integration
<code">pip install pymongo
<code">from pymongo import MongoClient
from datetime import datetime
# Connect — identical to MongoDB connection
client = MongoClient(
"mongodb://localhost:27017/",
username="ferretdb",
password="StrongFerretDbPassword!",
authSource="admin",
authMechanism="PLAIN",
)
db = client["myapp"]
users = db["users"]
# CRUD operations — standard pymongo, works on FerretDB unchanged
user_id = users.insert_one({
"name": "David",
"email": "david@example.com",
"created_at": datetime.now(),
"metadata": {"source": "web", "referral": "google"},
}).inserted_id
# Find with filters
recent_users = list(users.find(
{"created_at": {"$gte": datetime(2025, 1, 1)}},
{"name": 1, "email": 1, "_id": 0}
).sort("name", 1).limit(10))
# Update
users.update_one(
{"_id": user_id},
{"$set": {"verified": True}}
)
# Aggregation pipeline
pipeline = [
{"$match": {"verified": True}},
{"$group": {"_id": "$metadata.source", "count": {"$sum": 1}}},
{"$sort": {"count": -1}},
]
results = list(users.aggregate(pipeline))
Step 5: Node.js Integration
<code">npm install mongodb
<code">import { MongoClient } from 'mongodb';
const client = new MongoClient('mongodb://localhost:27017/', {
auth: { username: 'ferretdb', password: 'StrongFerretDbPassword!' },
authMechanism: 'PLAIN',
authSource: 'admin',
});
await client.connect();
const db = client.db('myapp');
const products = db.collection('products');
// Insert
await products.insertOne({
name: 'VPS Hosting',
price: 12.99,
category: 'hosting',
specs: { ram: 2, cpu: 2, storage: 40 },
});
// Query with projection
const hostingProducts = await products.find(
{ category: 'hosting', price: { $lte: 20 } },
{ projection: { name: 1, price: 1 } }
).toArray();
await client.close();
Step 6: What’s Stored in PostgreSQL
<code"># See how FerretDB stores MongoDB documents in PostgreSQL:
docker exec ferretdb-postgres psql -U ferretdb ferretdb
-- FerretDB creates a schema per database
\dn
-- Shows: myapp, ferretdb (system)
-- Each collection is a PostgreSQL table
\dt myapp.*
-- Shows: myapp.users, myapp.products
-- Documents stored as JSONB
SELECT _jsonb FROM myapp.users LIMIT 3;
-- Returns: {"_id": {"$o": "..."}, "name": "Alice", "email": "..."}
-- Can query directly with PostgreSQL!
SELECT _jsonb->>'name', _jsonb->>'email'
FROM myapp.users
WHERE _jsonb->>'email' = 'alice@example.com';
Step 7: Migrate from MongoDB
<code"># Export from MongoDB:
mongodump --host mongodb-server --db myapp --out /tmp/dump/
# Import to FerretDB:
mongorestore --host localhost:27017 \
--username ferretdb \
--password StrongFerretDbPassword! \
--authenticationMechanism PLAIN \
--authenticationDatabase admin \
/tmp/dump/
Getting Started
FerretDB with PostgreSQL uses 200–400 MB RAM total. A 2 GB Ubuntu VPS at VPS.DO handles FerretDB for most small to medium MongoDB workloads. The PostgreSQL backend means you benefit from PostgreSQL’s mature storage engine, VACUUM, EXPLAIN ANALYZE, and backup tools — familiar to any PostgreSQL DBA.
Conclusion
FerretDB enables MongoDB-compatible document storage on PostgreSQL — maintaining MongoDB client library compatibility while running on an Apache 2.0 licensed, PostgreSQL-backed store. For teams using MongoDB primarily for its flexible document model rather than complex aggregations or MongoDB-specific features, FerretDB provides a license-clean migration path. The PostgreSQL backend makes backup, restore, monitoring, and administration familiar to any team with PostgreSQL experience.