Migrating from MongoDB to FerretDB
Short version: FerretDB implements the MongoDB wire protocol on top of PostgreSQL, so your driver and your mongodb:// connection string stay as they are, and the data moves with mongodump and mongorestore, or in one pass through the Atlas migration page if you are landing on Layerbase Cloud. The copy is the mechanical part. The real work is the compatibility check, because $lookup, $graphLookup, change streams, $text search, capped collections, $merge and $out, $jsonSchema validation, and time-series collections are not supported, so grep for them before you touch any infrastructure. If none of them appear in your code, the migration is a connection-string change and a test run; if any of them are load-bearing, the right answer is to stay on MongoDB. Worth knowing before you plan around it: Layerbase does not host MongoDB itself, for licensing reasons, so FerretDB is the document engine in the cloud and the MongoDB card in the create flow provisions one.
If you've read our MongoDB vs FerretDB comparison, you know FerretDB implements the MongoDB wire protocol on top of PostgreSQL. Same mongodb:// connection string, same driver, Apache 2.0 licensed. But knowing that FerretDB exists and actually migrating a production app to it are two different things.
Unlike Redis to Valkey, where you literally swap the connection string and everything works, MongoDB to FerretDB has real compatibility gaps. FerretDB covers a large subset of the MongoDB API, but it is not a complete drop-in. The migration is feasible for many applications. You just need to check your queries first.
Contents
- What Works Out of the Box
- What Doesn't Work Yet
- Check Your Codebase
- Set Up FerretDB with the Layerbase CLI
- Migrate Your Data
- Point Your App at FerretDB
- The PostgreSQL Bonus
- When to Stay on MongoDB
- FAQ
- Wrapping Up
What Works Out of the Box
FerretDB supports the core operations that most applications rely on. If your codebase uses standard CRUD and basic aggregation, the migration is straightforward.
CRUD operations:
insertOne,insertManyfind,findOnewith projections and sortingupdateOne,updateManywith$set,$unset,$inc,$push,$pull,$addToSetdeleteOne,deleteManyreplaceOne
Query operators:
- Comparison:
$eq,$ne,$gt,$gte,$lt,$lte,$in,$nin - Logical:
$and,$or,$not,$nor - Element:
$exists,$type - Array:
$elemMatch,$size,$all - Regex:
$regex
Aggregation stages:
$match,$group,$sort,$project,$unwind$limit,$skip,$count
Other:
- Array queries (matching elements, nested arrays)
- Dot notation for nested documents
- Index creation (
createIndex) countDocuments,estimatedDocumentCountdistinct
This covers the majority of what typical CRUD applications use. If your app inserts documents, queries them with filters, runs some aggregation for reporting, and updates records, you're likely in the clear.
What Doesn't Work Yet
Here is where you need to pay attention. These MongoDB features are not supported in FerretDB as of early 2026:
| Feature | MongoDB | FerretDB | Workaround |
|---|---|---|---|
$lookup | Cross-collection joins in aggregation | Not supported | Two queries joined in application code, or query PostgreSQL directly |
$graphLookup | Recursive graph traversal | Not supported | Application-level recursion, or PostgreSQL recursive CTEs |
| Change streams | Real-time document change notifications | Not supported | PostgreSQL LISTEN/NOTIFY |
$text search | Built-in text indexes and search | Not supported | PostgreSQL tsvector/tsquery, or a search engine like Meilisearch |
| Capped collections | Fixed-size, insertion-order collections | Not supported | Application-level cleanup, or PostgreSQL partitioning with retention policies |
$merge / $out | Write aggregation results to a collection | Not supported | Fetch results in app code and insert into target collection |
| Schema validation | $jsonSchema on createCollection | Not supported | Application-level validation, or PostgreSQL constraints on the underlying table |
| Time-series collections | Optimized time-series storage | Not supported | PostgreSQL with TimescaleDB extension, or a purpose-built time-series DB like QuestDB or InfluxDB |
| Atlas Search | Full-text and vector search (Atlas only) | Not supported | PostgreSQL full-text search, pgvector, or dedicated search engines |
The FerretDB team publishes a compatibility page that tracks supported commands and operators. Bookmark it and check before migrating.
Check Your Codebase
Before you touch any infrastructure, grep your codebase for unsupported operations. This takes five minutes and tells you exactly how feasible the migration is.
# Search for unsupported MongoDB features
grep -rn '\$lookup' src/
grep -rn '\$graphLookup' src/
grep -rn '\.watch(' src/
grep -rn '\$text' src/
grep -rn '\$merge' src/
grep -rn '\$out' src/
grep -rn 'capped.*true' src/
grep -rn '\$jsonSchema' src/If none of those return results, your migration path is clean. Swap the connection string, run your test suite, and you're done.
If they do return results, you need to assess each usage:
$lookupin a few places? Refactor to two queries joined in your application code. It's more code, but it works identically on both engines.- Change streams for cache invalidation? Switch to polling, or use PostgreSQL
LISTEN/NOTIFYafter migrating. $textfor search? This is often the hardest one to replace inline. Consider adding Meilisearch or using PostgreSQL full-text search on the underlying tables.
The key question: are the unsupported features load-bearing in your application, or are they convenience features you can work around?
Set Up FerretDB with the Layerbase CLI
The fastest way to test the migration locally is the Layerbase CLI (formerly SpinDB). One CLI, no Docker, no manual configuration. (What is the Layerbase CLI?)
Install the Layerbase CLI:
npm i -g layerbase # npm
pnpm add -g layerbase # pnpmCreate a FerretDB instance:
lbase create ferret-migration -e ferretdb --startThe Layerbase CLI downloads FerretDB, provisions the PostgreSQL backend, and starts the server. Get the connection URL:
lbase url ferret-migrationmongodb://127.0.0.1:27018That's a standard mongodb:// URL. Your existing MongoDB driver connects to it without any code changes.
Migrate Your Data
If you're moving to Layerbase Cloud, you can skip the manual steps below: paste your MongoDB connection string on the MongoDB Atlas migration page and Layerbase copies your collections, documents, and indexes into a managed FerretDB database, verifies the document counts against your source, and reports anything it couldn't bring across. It works with Atlas and self-hosted MongoDB alike.
For a local or self-managed FerretDB, use mongodump to export your data from MongoDB and mongorestore to import it into FerretDB. These are standard MongoDB tools, and FerretDB supports the wire protocol they use.
Step 1: Dump from MongoDB
mongodump --uri="mongodb://localhost:27017" --db=myapp --out=./dumpThis creates a ./dump/myapp/ directory with BSON files for each collection.
If your MongoDB instance requires authentication:
mongodump --uri="mongodb://user:pass@your-mongo-host:27017/myapp?authSource=admin" --out=./dumpStep 2: Restore into FerretDB
mongorestore --uri="mongodb://localhost:27018" --db=myapp ./dump/myapp/FerretDB accepts the same mongorestore protocol. Your documents get stored as JSONB in the underlying PostgreSQL database.
Step 3: Verify the data
Connect with mongosh and spot-check:
mongosh "mongodb://localhost:27018/myapp"db.users.countDocuments()
db.users.findOne()
db.orders.countDocuments()Compare the counts and a few sample documents against your MongoDB source. If they match, your data is in FerretDB.
Point Your App at FerretDB
Update your connection string. That's it. Your MongoDB driver doesn't know or care that the backend changed.
// Before
const MONGO_URL = 'mongodb://localhost:27017/myapp'
// After
const MONGO_URL = 'mongodb://localhost:27018/myapp'Now run your test suite:
pnpm testIf all tests pass, you're migrated. If some tests fail, the failures will point you to exactly which MongoDB features you're using that FerretDB doesn't support yet.
This is why running tests is the real migration step. The data transfer is mechanical. The compatibility check is what matters.
The PostgreSQL Bonus
Once your data is in FerretDB, it lives in PostgreSQL. This unlocks things MongoDB can't offer.
Query with SQL. Your documents are stored as JSONB. You can query them with standard SQL:
SELECT _jsonb->>'title' AS title, _jsonb->>'status' AS status
FROM myapp.tasks_aaa30e43
WHERE _jsonb->>'priority' = 'high';The table names are auto-generated by FerretDB, but you can find them with \dt in psql.
Use pg_dump for backups. Your existing PostgreSQL backup scripts work on FerretDB's data. No new tools, no new processes:
pg_dump -h localhost -U postgres ferretdb_db > backup.sqlAccess the extension ecosystem. PostGIS for geospatial queries. pgvector for embeddings. pg_cron for scheduled jobs. TimescaleDB for time-series. These extensions work alongside your FerretDB data because it's all PostgreSQL under the hood.
Consolidate infrastructure. If you're already running PostgreSQL for your relational data, FerretDB means you don't need a second database system. One backup strategy, one monitoring setup, one set of operational playbooks.
When to Stay on MongoDB
Be honest with yourself about your requirements. FerretDB is not ready for every workload.
Stay on MongoDB if:
- You rely on change streams for real-time features (live dashboards, event-driven architectures)
- You use
$lookupheavily across many collections and refactoring would be impractical - You depend on Atlas Search for full-text or vector search
- You use time-series collections for IoT or metrics data
- Write throughput is critical and you need WiredTiger's purpose-built performance
- Your team is invested in the Atlas ecosystem (Charts, Realm, App Services)
FerretDB is actively developing. Features like $lookup and change streams may arrive in future releases. But "may arrive later" is not a migration plan. Base your decision on what works today.
FAQ
How do I find out whether my app will actually run on FerretDB?
Grep first, then run your tests. The grep list in Check Your Codebase takes five minutes and tells you whether any unsupported feature is in the codebase at all. After that, point a local FerretDB instance at your test suite: a failing test names the exact operation FerretDB does not implement, which is a far better inventory than reading a compatibility table and guessing. The data transfer is mechanical, so this is the step that decides whether the migration happens.
What comes across in the copy, and what gets skipped?
Collections, documents, and ordinary indexes come across as they are. An index FerretDB cannot create is skipped in full rather than created without its options, and it is named in the migration report so you can decide whether to rebuild it by hand. Views and time-series collections are not copied and are listed the same way. Document counts are verified against the source when the copy finishes, and there is a ceiling: a collection over five million documents is refused, so a bigger move needs a conversation with support first.
Does my MongoDB need to be offline while it copies?
It keeps serving, but the read is against your live database rather than a point-in-time snapshot, so writes landing partway through can arrive unevenly across collections. Copy from a quiet database, or pause writes for the duration. The cutover afterward is a connection string, since your driver does not know the backend changed.
What do I use instead of change streams and $text once I am on FerretDB?
The replacements are all on the PostgreSQL side, which is the compensation for the gaps. Change streams become LISTEN and NOTIFY, or polling if the use case is cache invalidation. $text becomes PostgreSQL full-text search over the underlying JSONB, or a dedicated engine like Meilisearch if search is a real feature rather than a lookup box. $lookup becomes two queries joined in application code, or a SQL join against the tables directly.
Why not just run MongoDB on Layerbase and skip all of this?
MongoDB's license does not permit it, which is the whole reason FerretDB is here. The MongoDB card in the create flow provisions FerretDB on the same wire protocol, so the connection string and driver you would have used still apply. If the compatibility gaps rule FerretDB out for your workload, the correct move is to stay where you are rather than force the migration.
Wrapping Up
Migrating from MongoDB to FerretDB is straightforward if your application uses standard CRUD operations and basic aggregation. The process is: check your codebase for unsupported features, set up FerretDB, dump and restore your data, swap the connection string, run your tests.
The compatibility gaps are real, and you should respect them. But for applications that don't use $lookup, change streams, or text search, the migration removes the SSPL licensing concern and consolidates your data onto PostgreSQL infrastructure.
Manage your local instances:
lbase stop ferret-migration # Stop FerretDB
lbase start ferret-migration # Start FerretDB
lbase connect ferret-migration # Connect with mongosh
lbase list # See all your database instancesThe Layerbase CLI supports 20+ engines, so you can test both MongoDB and FerretDB side by side locally before committing to the migration. For a hosted option, Layerbase Cloud provisions FerretDB in seconds (MongoDB itself is not creatable in the cloud for licensing reasons; the MongoDB card in the create flow provisions FerretDB on the same wire protocol):
Or install Layerbase Desktop for a visual interface to manage your local databases.
Keep reading
- MongoDB Atlas alternatives: flat pricing and a document database you can branchWhat you actually get when you leave MongoDB Atlas for managed FerretDB on Layerbase: the same wire protocol and driver, a flat monthly price instead of a per-tier meter, branching Atlas does not offer, and an honest list of the cases where you should stay put.
- MongoDB vs FerretDB on the same hardware: the benchmark, and what we had to fix to run it fairlyYCSB against MongoDB 8.0 and FerretDB 2.7 on the exact hardware behind our $65/mo dedicated preset. Once our own tuning was right, FerretDB held 3-4x MongoDB throughput on the mixed workload and about 5x on reads. The corrected numbers, what had to be fixed first, and what we are not claiming.
- Run FerretDB on Windows (No Docker, No WSL)FerretDB v2 needs a PostgreSQL extension that is not on Windows yet. We built custom binaries to run FerretDB v1 natively on Windows, no Docker or WSL.
- 7 reasons to choose FerretDB over MongoDBFerretDB gives you the MongoDB API on top of PostgreSQL, under an Apache 2.0 license. Here are seven concrete reasons teams pick it over MongoDB, and an honest list of when you should not.