Core Concepts

MongoDB Compatibility and Differences

Understand what FerretDB supports, where it differs from MongoDB, and how to migrate an existing MongoDB application.

FerretDB Compatibility Status

FerretDB aims to be compatible with the MongoDB 6.x API. As of 2025, most common MongoDB operations are supported:

Fully Supported

  • CRUD operations: insertOne, insertMany, find, findOne, updateOne, updateMany, deleteOne, deleteMany
  • Comparison operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin
  • Logical operators: $and, $or, $not, $nor
  • Update operators: $set, $unset, $inc, $push, $pull, $addToSet
  • Aggregation pipeline: $match, $group, $sort, $limit, $skip, $project
  • Indexes: single field, compound, text (basic)

Not Yet Supported / Limited

  • Transactions (multi-document) — in progress
  • Change Streams — not supported
  • Full aggregation pipeline coverage — some operators missing
  • Geospatial queries — basic support
  • GridFS — not supported

Check the [FerretDB compatibility table](https://docs.ferretdb.io/reference/supported-commands/) for the current status.

Practical Differences

ObjectId Handling

FerretDB generates ObjectIds that look different internally but behave the same from the application's perspective:

javascript
// This works identically on MongoDB and FerretDB
const result = await collection.insertOne({ name: 'Alice' });
console.log(result.insertedId); // ObjectId - same API

Data Inspection in PostgreSQL

The biggest operational difference: you can inspect and query your data directly in PostgreSQL:

sql
-- In psql, FerretDB stores documents in a JSONB column
SELECT * FROM myapp.users LIMIT 5;

-- Query with PostgreSQL's JSONB operators directly
SELECT data->>'name', data->>'email'
FROM myapp.users
WHERE data->>'role' = 'admin';

-- This is powerful for debugging, analytics, and migrations

Migrating from MongoDB to FerretDB

Step 1: Export from MongoDB

bash
mongodump --uri "mongodb://your-mongo/myapp" --out ./dump

Step 2: Start FerretDB

bash
docker-compose up -d

Step 3: Import to FerretDB

bash
mongorestore --uri "mongodb://localhost:27017/myapp" ./dump/myapp

Step 4: Update connection string

javascript
// Before
const client = new MongoClient('mongodb://mongo-host:27017/myapp');

// After
const client = new MongoClient('mongodb://localhost:27017/myapp');
// That's it — no other code changes for supported operations

FerretDB in AI Applications

FerretDB is a good choice for AI applications that:

  • Already use MongoDB and want to migrate to a truly open-source stack
  • Want to store document data (like conversation histories or prompt templates) alongside relational data in PostgreSQL
  • Need SQL analytics on document data without a separate data warehouse
javascript
// Store LLM conversation history as documents
const conversations = db.collection('conversations');

await conversations.insertOne({
  sessionId: 'sess-abc123',
  userId: 'user-42',
  messages: [
    { role: 'user', content: 'Explain RAG pipelines', ts: new Date() },
    { role: 'assistant', content: 'RAG (Retrieval Augmented Generation)...', ts: new Date() },
  ],
  model: 'claude-opus-4-5',
  tokenCount: 450,
  createdAt: new Date(),
});

// Retrieve conversation history
const history = await conversations
  .find({ userId: 'user-42' })
  .sort({ createdAt: -1 })
  .limit(10)
  .toArray();

// Meanwhile, in PostgreSQL you can run analytics:
// SELECT data->>'model', COUNT(*), SUM((data->>'tokenCount')::int)
// FROM myapp.conversations
// GROUP BY data->>'model';

FerretDB vs. DocumentDB (Amazon)

Amazon DocumentDB is also MongoDB-compatible but is closed-source, AWS-only, and has its own compatibility gaps. FerretDB is open-source, runs anywhere PostgreSQL runs, and is community-driven. For teams avoiding vendor lock-in, FerretDB is the more principled choice.

Example

javascript
// Migration test: run this against both MongoDB and FerretDB
import { MongoClient } from 'mongodb';

async function testCompatibility(uri) {
  const client = new MongoClient(uri);
  await client.connect();

  const col = client.db('test').collection('items');
  await col.deleteMany({});  // Clean slate

  // CRUD
  await col.insertMany([
    { name: 'A', score: 10, tags: ['x', 'y'] },
    { name: 'B', score: 20, tags: ['y', 'z'] },
    { name: 'C', score: 30, tags: ['x', 'z'] },
  ]);

  const docs = await col.find({ score: { $gt: 10 } }).sort({ score: -1 }).toArray();
  console.log('Query result count:', docs.length); // Should be 2

  await col.updateOne({ name: 'A' }, { $inc: { score: 5 } });
  const updated = await col.findOne({ name: 'A' });
  console.log('Updated score:', updated.score); // Should be 15

  await client.close();
}

Want to run this code interactively?

Try in Compiler