FerretDB on a VPS: MongoDB-Compatible Database on PostgreSQL Without MongoDB Licensing

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.

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!