Deploying FerretDB
Introduction
FerretDB is an innovative open-source proxy that translates MongoDB wire protocol queries to SQL, allowing you to use MongoDB drivers and tools with PostgreSQL as the database backend. Created as an open-source alternative to MongoDB, FerretDB provides a truly open-source solution that gives you MongoDB compatibility without vendor lock-in.
Developed by FerretDB Inc. and first released in 2021, FerretDB bridges the gap between MongoDB’s developer-friendly API and PostgreSQL’s robustness and reliability. It acts as a stateless proxy, converting MongoDB queries into SQL statements that PostgreSQL can execute, giving you the best of both worlds.
FerretDB excels at:
- MongoDB Compatibility: Drop-in replacement for MongoDB, works with existing MongoDB drivers and tools
- PostgreSQL Backend: Leverages PostgreSQL’s proven reliability, ACID compliance, and mature ecosystem
- True Open Source: Licensed under Apache 2.0, no vendor lock-in or proprietary features
- Stateless Architecture: FerretDB itself stores no data, making it easy to scale and maintain
- Developer Friendly: Use familiar MongoDB syntax with the reliability of PostgreSQL
- Cost Effective: Avoid MongoDB licensing costs while maintaining compatibility
- Data Ownership: Full control over your data with PostgreSQL’s transparent storage
- Ecosystem Integration: Works with existing PostgreSQL tools, backups, and monitoring solutions
- SQLite Support: Also supports SQLite backend for lightweight deployments
- Standards Compliant: Built on open standards rather than proprietary protocols
Common use cases include migrating from MongoDB while maintaining application compatibility, building new applications with MongoDB-like APIs backed by PostgreSQL, avoiding MongoDB licensing restrictions, and leveraging PostgreSQL features while using MongoDB tooling.
This comprehensive guide walks you through deploying FerretDB on Klutch.sh using Docker, including detailed installation steps, sample configurations, connection examples, and production-ready best practices for persistent storage and PostgreSQL integration.
Prerequisites
Before you begin, ensure you have the following:
- A Klutch.sh account
- A GitHub account with a repository for your FerretDB project
- Docker installed locally for testing (optional but recommended)
- Basic understanding of Docker, MongoDB, and PostgreSQL
- A PostgreSQL database (can be deployed separately on Klutch.sh or use an external provider)
Installation and Setup
Step 1: Create Your Project Directory
First, create a new directory for your FerretDB deployment project:
mkdir ferretdb-klutchcd ferretdb-klutchgit initStep 2: Create the Dockerfile
Create a Dockerfile in your project root directory. This will define your FerretDB container configuration:
FROM ghcr.io/ferretdb/ferretdb:latest
# Expose the default FerretDB/MongoDB portEXPOSE 27017
# FerretDB configuration is done via environment variables# These will be set in the Klutch.sh dashboard:# - FERRETDB_POSTGRESQL_URL: Connection string to PostgreSQL backend# - FERRETDB_TELEMETRY: Set to "disable" to turn off telemetry# - FERRETDB_HANDLER: Database handler (default: "pg" for PostgreSQL)# - FERRETDB_MODE: Operation mode (default: "normal")# - FERRETDB_DEBUG_ADDR: Debug endpoint address (optional)
# The container will start FerretDB automatically# No custom CMD needed as the base image handles itNote: FerretDB uses the latest stable release from GitHub Container Registry. The image is maintained by the FerretDB team and regularly updated.
Step 3: Prepare PostgreSQL Backend
FerretDB requires a PostgreSQL database as its backend. You have several options:
Option A: Deploy PostgreSQL on Klutch.sh (Recommended)
- Follow the PostgreSQL deployment guide to create a PostgreSQL instance on Klutch.sh
- Note the connection details (host, port, username, password, database name)
- Your connection string will look like:
postgres://username:password@postgres-app.klutch.sh:8000/ferretdb
Option B: Use External PostgreSQL Provider
You can use any PostgreSQL provider like AWS RDS, Azure Database, Heroku Postgres, or Neon. Just ensure your connection string is accessible from Klutch.sh.
Option C: SQLite Backend (for testing/development)
For lightweight testing, FerretDB can use SQLite:
FROM ghcr.io/ferretdb/ferretdb:latest
# For SQLite backendENV FERRETDB_HANDLER=sqliteENV FERRETDB_SQLITE_URL=file:/state/
EXPOSE 27017
# Create directory for SQLite dataRUN mkdir -p /stateFor this guide, we’ll focus on the PostgreSQL backend which is recommended for production.
Step 4: (Optional) Create a Custom Entrypoint Script
If you need additional initialization or custom configuration, create an entrypoint.sh script:
#!/bin/sh# entrypoint.sh - Custom entrypoint for FerretDB
# Wait for PostgreSQL to be ready (optional)echo "Waiting for PostgreSQL to be ready..."until pg_isready -h ${PG_HOST} -p ${PG_PORT} -U ${PG_USER}; do echo "PostgreSQL is unavailable - sleeping" sleep 2done
echo "PostgreSQL is ready - starting FerretDB"
# Start FerretDBexec /ferretdbUpdate your Dockerfile to use the custom entrypoint:
FROM ghcr.io/ferretdb/ferretdb:latest
# Install PostgreSQL client tools (for pg_isready)USER rootRUN apk add --no-cache postgresql-client
# Copy custom entrypointCOPY entrypoint.sh /entrypoint.shRUN chmod +x /entrypoint.sh
EXPOSE 27017
USER ferretdbENTRYPOINT ["/entrypoint.sh"]Step 5: Test Locally (Optional)
Before deploying to Klutch.sh, you can test your FerretDB setup locally. First, start a PostgreSQL container:
# Start PostgreSQL for testingdocker run -d \ --name postgres-test \ -e POSTGRES_DB=ferretdb \ -e POSTGRES_USER=ferretdb \ -e POSTGRES_PASSWORD=ferretdb_password \ -p 5432:5432 \ postgres:16-alpine
# Wait a moment for PostgreSQL to be readysleep 5
# Build the FerretDB Docker imagedocker build -t my-ferretdb .
# Run FerretDB containerdocker run -d \ --name ferretdb-test \ -p 27017:27017 \ -e FERRETDB_POSTGRESQL_URL="postgres://ferretdb:ferretdb_password@host.docker.internal:5432/ferretdb" \ -e FERRETDB_TELEMETRY=disable \ my-ferretdb
# Test connection using mongosh (if installed)mongosh "mongodb://127.0.0.1:27017/testdb"
# Inside mongosh:# db.testCollection.insertOne({name: "test", value: 42})# db.testCollection.find()# exit
# Cleanup when donedocker stop ferretdb-test postgres-testdocker rm ferretdb-test postgres-testStep 6: Push to GitHub
Commit your Dockerfile and any configuration files to your GitHub repository:
git add Dockerfile entrypoint.shgit commit -m "Add FerretDB Dockerfile and configuration"git remote add origin https://github.com/yourusername/ferretdb-klutch.gitgit push -u origin mainConnecting to FerretDB
Once deployed, you can connect to your FerretDB instance using any MongoDB driver or tool. Since Klutch.sh routes TCP traffic through port 8000, use the following format:
Connection String
Standard MongoDB Connection String:
mongodb://example-app.klutch.sh:8000/mydatabaseWith Authentication (if configured in PostgreSQL):
mongodb://username:password@example-app.klutch.sh:8000/mydatabase?authMechanism=PLAINReplace:
example-app.klutch.shwith your actual Klutch.sh app URLmydatabasewith your database nameusernameandpasswordwith your PostgreSQL credentials (if using authentication)
Important: FerretDB uses PLAIN authentication mechanism which passes credentials to the PostgreSQL backend. Ensure your connection uses TLS in production environments.
Example Connection Code
Node.js (using mongodb driver):
const { MongoClient } = require('mongodb');
const uri = 'mongodb://example-app.klutch.sh:8000/myapp';const client = new MongoClient(uri);
async function run() { try { await client.connect(); console.log('Connected to FerretDB');
const database = client.db('myapp'); const collection = database.collection('users');
// Insert a document const result = await collection.insertOne({ name: 'John Doe', email: 'john@example.com', age: 30, createdAt: new Date() }); console.log('Inserted document with _id:', result.insertedId);
// Find documents const users = await collection.find({}).toArray(); console.log('All users:', users);
// Update a document await collection.updateOne( { name: 'John Doe' }, { $set: { age: 31 } } );
// Find one document const user = await collection.findOne({ name: 'John Doe' }); console.log('Updated user:', user);
// Delete a document // await collection.deleteOne({ name: 'John Doe' });
} finally { await client.close(); }}
run().catch(console.error);Node.js (using mongoose):
const mongoose = require('mongoose');
const uri = 'mongodb://example-app.klutch.sh:8000/myapp';
mongoose.connect(uri, { // FerretDB compatible options directConnection: true,}) .then(() => console.log('Connected to FerretDB via Mongoose')) .catch(err => console.error('Connection error:', err));
// Define a schemaconst userSchema = new mongoose.Schema({ name: { type: String, required: true }, email: { type: String, required: true, unique: true }, age: { type: Number }, createdAt: { type: Date, default: Date.now }});
const User = mongoose.model('User', userSchema);
// Create a new userasync function createUser() { const user = new User({ name: 'Jane Smith', email: 'jane@example.com', age: 28 });
try { const savedUser = await user.save(); console.log('User saved:', savedUser); } catch (err) { console.error('Error saving user:', err); }}
createUser();Python (using pymongo):
from pymongo import MongoClientfrom datetime import datetime
# Connect to FerretDBuri = "mongodb://example-app.klutch.sh:8000/myapp"client = MongoClient(uri)
# Access database and collectiondb = client.myappusers = db.users
# Insert a documentresult = users.insert_one({ 'name': 'Alice Johnson', 'email': 'alice@example.com', 'age': 25, 'createdAt': datetime.now()})print(f'Inserted document ID: {result.inserted_id}')
# Query documentsall_users = list(users.find())for user in all_users: print(f"User: {user['name']}, Email: {user['email']}")
# Update a documentusers.update_one( {'name': 'Alice Johnson'}, {'$set': {'age': 26}})
# Find one documentuser = users.find_one({'name': 'Alice Johnson'})print(f'Updated user: {user}')
# Close connectionclient.close()Go (using mongo-go-driver):
package main
import ( "context" "fmt" "log" "time"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options")
func main() { uri := "mongodb://example-app.klutch.sh:8000/myapp"
clientOptions := options.Client().ApplyURI(uri).SetDirect(true) client, err := mongo.Connect(context.TODO(), clientOptions) if err != nil { log.Fatal(err) } defer client.Disconnect(context.TODO())
// Access collection collection := client.Database("myapp").Collection("users")
// Insert a document doc := bson.M{ "name": "Bob Smith", "email": "bob@example.com", "age": 32, "createdAt": time.Now(), } result, err := collection.InsertOne(context.TODO(), doc) if err != nil { log.Fatal(err) } fmt.Printf("Inserted document ID: %v\n", result.InsertedID)
// Query documents cursor, err := collection.Find(context.TODO(), bson.M{}) if err != nil { log.Fatal(err) } defer cursor.Close(context.TODO())
for cursor.Next(context.TODO()) { var user bson.M if err := cursor.Decode(&user); err != nil { log.Fatal(err) } fmt.Printf("User: %v\n", user) }}Java (using MongoDB Java Driver):
import com.mongodb.client.*;import com.mongodb.ConnectionString;import com.mongodb.MongoClientSettings;import org.bson.Document;import java.util.Date;
public class FerretDBConnection { public static void main(String[] args) { String uri = "mongodb://example-app.klutch.sh:8000/myapp";
ConnectionString connString = new ConnectionString(uri); MongoClientSettings settings = MongoClientSettings.builder() .applyConnectionString(connString) .build();
try (MongoClient mongoClient = MongoClients.create(settings)) { MongoDatabase database = mongoClient.getDatabase("myapp"); MongoCollection<Document> collection = database.getCollection("users");
// Insert a document Document user = new Document("name", "Carol White") .append("email", "carol@example.com") .append("age", 29) .append("createdAt", new Date()); collection.insertOne(user); System.out.println("Inserted document");
// Query documents FindIterable<Document> users = collection.find(); for (Document doc : users) { System.out.println("User: " + doc.toJson()); } } }}PHP (using MongoDB PHP Library):
<?phprequire 'vendor/autoload.php';
use MongoDB\Client;
$uri = 'mongodb://example-app.klutch.sh:8000/myapp';$client = new Client($uri);
$collection = $client->myapp->users;
// Insert a document$insertResult = $collection->insertOne([ 'name' => 'David Brown', 'email' => 'david@example.com', 'age' => 35, 'createdAt' => new MongoDB\BSON\UTCDateTime()]);
printf("Inserted document with ID: %s\n", $insertResult->getInsertedId());
// Find documents$cursor = $collection->find();
foreach ($cursor as $document) { printf("User: %s, Email: %s\n", $document['name'], $document['email']);}
// Update a document$updateResult = $collection->updateOne( ['name' => 'David Brown'], ['$set' => ['age' => 36]]);
printf("Modified %d document(s)\n", $updateResult->getModifiedCount());?>Deploying to Klutch.sh
Now that your FerretDB project is ready and pushed to GitHub, follow these steps to deploy it on Klutch.sh.
Deployment Steps
-
Deploy PostgreSQL Backend (if not already done)
Before deploying FerretDB, ensure you have a PostgreSQL database running. Follow the PostgreSQL deployment guide to set one up on Klutch.sh. Make note of:
- PostgreSQL host URL (e.g.,
postgres-app.klutch.sh) - Port (8000 for Klutch.sh TCP apps)
- Database name (e.g.,
ferretdb) - Username and password
- PostgreSQL host URL (e.g.,
-
Log in to Klutch.sh
Navigate to klutch.sh/app and sign in to your account.
-
Create a New Project
Go to Create Project and give your project a meaningful name (e.g., “FerretDB Proxy”).
-
Create a New App
Navigate to Create App and configure the following settings:
-
Select Your Repository
- Choose GitHub as your Git source
- Select the repository containing your Dockerfile
- Choose the branch you want to deploy (usually
mainormaster)
-
Configure Traffic Type
- Traffic Type: Select TCP (FerretDB uses the MongoDB wire protocol which requires TCP)
- Internal Port: Set to
27017(the default MongoDB/FerretDB port that your container listens on)
-
Set Environment Variables
Add the following environment variables for your FerretDB configuration:
Required:
FERRETDB_POSTGRESQL_URL: The connection string to your PostgreSQL backend- Format:
postgres://username:password@postgres-app.klutch.sh:8000/ferretdb - Replace with your actual PostgreSQL connection details
- Format:
Optional:
FERRETDB_TELEMETRY: Set todisableto opt out of anonymous telemetry (default: enabled)FERRETDB_HANDLER: Database handler type, set topgfor PostgreSQL (default:pg)FERRETDB_MODE: Operation mode -normal,proxy, ordiff-normal(default:normal)FERRETDB_STATE_DIR: Directory for internal state (default:/state)
Example Configuration:
FERRETDB_POSTGRESQL_URL=postgres://ferretdb:mypassword@postgres-app.klutch.sh:8000/ferretdbFERRETDB_TELEMETRY=disableSecurity Note: Keep your PostgreSQL credentials secure. Never commit them to your repository.
-
Persistent Volumes (Optional for FerretDB)
FerretDB is stateless and doesn’t require persistent storage since all data is stored in PostgreSQL. However, if you want to persist internal state or logs:
- In the Volumes section, click “Add Volume”
- Mount Path: Enter
/state(for FerretDB state directory) - Size: 1GB is typically sufficient
-
Configure Additional Settings
- Region: Select the region closest to your PostgreSQL backend and users for optimal latency
- Compute Resources: FerretDB is lightweight; 256MB-512MB RAM is typically sufficient, scale up based on load
- Instances: Start with 1 instance (you can scale horizontally later if needed)
-
Deploy FerretDB
Click “Create” to start the deployment. Klutch.sh will:
- Automatically detect your Dockerfile in the repository root
- Build the Docker image
- Start your FerretDB container
- Connect to your PostgreSQL backend
- Assign a URL for MongoDB client connections
-
Verify Deployment
Once deployment is complete, you’ll receive a URL like
example-app.klutch.sh. Test your connection:Terminal window # Using mongosh (if installed locally)mongosh "mongodb://example-app.klutch.sh:8000/testdb"# Test with simple commandsdb.test.insertOne({message: "Hello FerretDB"})db.test.find() -
Access Your Database
Your FerretDB instance is now accessible at:
mongodb://example-app.klutch.sh:8000/mydatabaseUse this connection string in your applications with any MongoDB driver.
Production Best Practices
Architecture Considerations
FerretDB + PostgreSQL Deployment:
- Deploy FerretDB and PostgreSQL in the same region to minimize latency
- Use persistent volumes for PostgreSQL data (
/var/lib/postgresql/data) - FerretDB is stateless; focus performance tuning on PostgreSQL
- Consider connection pooling for high-traffic applications
Scaling Strategy:
- Scale FerretDB horizontally by deploying multiple instances
- Use a load balancer for distributing MongoDB connections
- Scale PostgreSQL vertically (CPU/RAM) for better performance
- Monitor PostgreSQL query performance and optimize indexes
Security Recommendations
- Use Strong Authentication: Always configure PostgreSQL with strong passwords
- Network Security: Keep FerretDB and PostgreSQL in the same private network when possible
- Connection Security: Use TLS/SSL for production connections
- Access Control: Implement PostgreSQL role-based access control (RBAC)
- Environment Variables: Never hardcode credentials; use Klutch.sh environment variables
- Regular Updates: Keep FerretDB and PostgreSQL images updated for security patches
- Audit Logging: Enable PostgreSQL audit logging for compliance requirements
- Principle of Least Privilege: Grant minimum necessary permissions to database users
Performance Optimization
PostgreSQL Backend:
- Indexing: Create appropriate indexes on frequently queried fields
- Connection Pooling: Use pgBouncer or built-in PostgreSQL connection pooling
- Resource Allocation: Allocate sufficient RAM for PostgreSQL cache (shared_buffers)
- Query Optimization: Use PostgreSQL EXPLAIN to analyze query performance
- Vacuuming: Regular VACUUM and ANALYZE operations for table maintenance
FerretDB Configuration:
- Connection Limits: Monitor and adjust PostgreSQL max_connections
- Query Timeout: Set appropriate query timeouts to prevent long-running queries
- Batch Operations: Use bulk insert/update operations when possible
- Connection Reuse: Implement connection pooling in your application
Monitoring Metrics:
- FerretDB connection count and response times
- PostgreSQL CPU, memory, and disk I/O
- Query execution times and slow query logs
- Database size growth and table statistics
- Connection pool utilization
- Network latency between FerretDB and PostgreSQL
Backup Strategy
Since FerretDB stores all data in PostgreSQL, focus your backup strategy on the PostgreSQL database:
# Backup PostgreSQL databasepg_dump -h postgres-app.klutch.sh -p 8000 -U ferretdb -d ferretdb > backup.sql
# Restore from backuppsql -h postgres-app.klutch.sh -p 8000 -U ferretdb -d ferretdb < backup.sqlBackup Best Practices:
- Automated daily backups of PostgreSQL database
- Multiple retention periods (daily, weekly, monthly)
- Offsite backup storage for disaster recovery
- Regular restore testing to verify backup integrity
- Use PostgreSQL point-in-time recovery (PITR) for critical data
- Document backup and restore procedures
Data Modeling
Considerations for FerretDB:
FerretDB translates MongoDB operations to PostgreSQL SQL. Some considerations:
// Embedded documents work well (1-to-few relationships)db.users.insertOne({ name: "John Doe", email: "john@example.com", addresses: [ { street: "123 Main St", city: "New York", zip: "10001" }, { street: "456 Oak Ave", city: "Boston", zip: "02101" } ]});
// For large arrays or 1-to-many relationships, consider separate collections// Users collectiondb.users.insertOne({ _id: 1, name: "John Doe", email: "john@example.com" });
// Orders collection with referencedb.orders.insertOne({ _id: 101, userId: 1, total: 99.99, items: ["item1", "item2"]});Best Practices:
- Keep documents reasonably sized (< 1MB when possible)
- Use indexes on frequently queried fields
- Avoid deeply nested documents (3-4 levels max)
- Consider denormalization vs normalization trade-offs
- Test query patterns with EXPLAIN for optimization
Monitoring and Observability
Key Metrics to Monitor:
// FerretDB build infodb.runCommand({ buildInfo: 1 })
// Server statusdb.runCommand({ serverStatus: 1 })
// Database statisticsdb.stats()
// Collection statisticsdb.myCollection.stats()PostgreSQL Monitoring:
-- Check active connectionsSELECT count(*) FROM pg_stat_activity;
-- Check database sizeSELECT pg_size_pretty(pg_database_size('ferretdb'));
-- Check table sizesSELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS sizeFROM pg_tablesORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESCLIMIT 10;
-- Check slow queries (if pg_stat_statements is enabled)SELECT query, mean_exec_time, callsFROM pg_stat_statementsORDER BY mean_exec_time DESCLIMIT 10;MongoDB Compatibility
FerretDB implements a subset of MongoDB features. Here’s what’s supported:
Supported Operations
CRUD Operations:
insertOne,insertManyfindOne,findwith basic queriesupdateOne,updateManydeleteOne,deleteManycountDocuments,estimatedDocumentCount
Query Operators:
- Comparison:
$eq,$ne,$gt,$gte,$lt,$lte,$in,$nin - Logical:
$and,$or,$not,$nor - Element:
$exists,$type - Array:
$size,$all
Update Operators:
- Field:
$set,$unset,$inc,$mul - Array:
$push,$pop,$addToSet
Aggregation:
- Basic aggregation pipeline support
$match,$group,$sort,$limit,$skip,$count- Common aggregation operators
Indexes:
- Single field indexes
- Compound indexes
- Unique indexes
Known Limitations
- Some advanced aggregation operators are not yet supported
- Transactions are not fully supported (work in progress)
- Change streams are not yet implemented
- Some MongoDB-specific features like sharding are not applicable
- GridFS is not currently supported
Check the official FerretDB documentation for the most up-to-date compatibility matrix.
Troubleshooting
Cannot Connect to FerretDB
- Verify you’re using the correct connection string with port 8000
- Ensure the internal port is set to 27017 in your app configuration
- Check that TCP traffic type is selected in Klutch.sh
- Verify FerretDB container is running and healthy
- Test PostgreSQL connectivity from FerretDB container
PostgreSQL Connection Issues
- Verify
FERRETDB_POSTGRESQL_URLenvironment variable is correct - Ensure PostgreSQL is accessible from the FerretDB container
- Check PostgreSQL connection limits (max_connections)
- Verify PostgreSQL username and password are correct
- Ensure the specified database exists in PostgreSQL
Authentication Failed
Error: authentication failed- FerretDB uses PostgreSQL credentials for authentication
- Ensure credentials in connection string match PostgreSQL user
- Use
authMechanism=PLAINin connection string if needed - Verify PostgreSQL user has necessary permissions
Unsupported Operation Error
Error: unsupported operation- Check FerretDB compatibility documentation for the operation
- Some MongoDB operations are not yet implemented
- Consider alternative approaches using supported operations
- Review FerretDB logs for specific unsupported feature details
Performance Issues
- Check PostgreSQL query performance (slow query log)
- Ensure appropriate indexes exist in PostgreSQL
- Monitor connection pool utilization
- Verify sufficient resources allocated to PostgreSQL
- Check network latency between FerretDB and PostgreSQL
- Review FerretDB logs for query translation issues
Data Not Persisting
- FerretDB is stateless; check PostgreSQL data persistence
- Verify PostgreSQL volume is correctly mounted at
/var/lib/postgresql/data - Check PostgreSQL logs for errors
- Ensure sufficient disk space in PostgreSQL volume
Viewing FerretDB Logs
To debug issues, check FerretDB logs in Klutch.sh:
- Navigate to your app in the Klutch.sh dashboard
- Go to the “Logs” section
- Look for error messages or warnings
- Common issues include PostgreSQL connection problems or unsupported operations
Checking PostgreSQL Backend
Connect directly to PostgreSQL to verify data storage:
# Connect to PostgreSQLpsql -h postgres-app.klutch.sh -p 8000 -U ferretdb -d ferretdb
# List schemas (FerretDB creates schemas for each database)\dn
# List tables in a schema\dt myapp.*
# View data in a tableSELECT * FROM myapp.users_<uuid>;
# Exit\qAdvanced Configuration
Custom FerretDB Modes
FerretDB supports different operation modes:
Normal Mode (default):
ENV FERRETDB_MODE=normalStandard operation mode for production use.
Proxy Mode:
ENV FERRETDB_MODE=proxyPasses unsupported operations through to PostgreSQL (experimental).
Diff Mode:
ENV FERRETDB_MODE=diff-normalCompares FerretDB results with actual MongoDB (for testing compatibility).
Debug and Logging
Enable debug logging for troubleshooting:
ENV FERRETDB_DEBUG_ADDR=:8088This exposes debug endpoints at port 8088 for metrics and profiling.
Using SQLite Backend (Testing/Development)
For lightweight testing without PostgreSQL:
FROM ghcr.io/ferretdb/ferretdb:latest
ENV FERRETDB_HANDLER=sqliteENV FERRETDB_SQLITE_URL=file:/state/
EXPOSE 27017
RUN mkdir -p /stateNote: SQLite backend is suitable for development/testing only, not production.
Migration from MongoDB
If migrating from MongoDB to FerretDB:
- Export MongoDB data:
mongodump --uri="mongodb://old-mongodb:27017/mydb" --out=/backup- Import into FerretDB:
mongorestore --uri="mongodb://example-app.klutch.sh:8000/mydb" /backup- Verify data:
# Count documents in each collectionmongosh "mongodb://example-app.klutch.sh:8000/mydb" --eval "db.getCollectionNames().forEach(c => print(c + ': ' + db[c].countDocuments()))"-
Update application connection string to point to FerretDB
-
Test thoroughly to ensure all operations work correctly
Use Cases
1. MongoDB Compatibility with PostgreSQL Reliability
Perfect for teams that:
- Want MongoDB’s developer experience with PostgreSQL’s maturity
- Need ACID guarantees and proven PostgreSQL reliability
- Want to leverage existing PostgreSQL expertise and tools
- Require open-source databases without licensing concerns
2. Migration from MongoDB
Ideal for:
- Reducing MongoDB licensing costs
- Avoiding vendor lock-in
- Maintaining application compatibility during migration
- Gradual transition to PostgreSQL-native operations
3. Multi-Database Strategy
Use FerretDB for:
- Document-oriented microservices backed by centralized PostgreSQL
- Unified backup and monitoring infrastructure
- Consistent security policies across all databases
- Simplified operational overhead
4. Development and Testing
Great for:
- Local development matching production MongoDB APIs
- Testing MongoDB applications without MongoDB installation
- CI/CD pipelines using PostgreSQL test databases
- Cost-effective testing environments
Additional Resources
- Klutch.sh Documentation
- Official FerretDB Documentation
- FerretDB GitHub Repository
- FerretDB Command Compatibility
- FerretDB Container Images (GitHub Container Registry)
- PostgreSQL on Klutch.sh Guide
- Klutch.sh Volumes Guide
- Klutch.sh Networking Guide
- FerretDB Blog
Conclusion
Deploying FerretDB to Klutch.sh with Docker provides a powerful MongoDB-compatible database solution backed by PostgreSQL’s reliability and proven track record. By following this guide, you’ve set up a production-ready FerretDB instance that gives you the best of both worlds: MongoDB’s developer-friendly API with PostgreSQL’s robustness, ACID compliance, and mature ecosystem.
With FerretDB on Klutch.sh, you can build modern applications using familiar MongoDB tools and drivers while maintaining full control over your data with PostgreSQL. Whether you’re migrating from MongoDB, starting a new project, or seeking an open-source alternative without vendor lock-in, FerretDB offers a compelling solution that combines flexibility, reliability, and true open-source freedom.