Skip to content

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:

Terminal window
mkdir ferretdb-klutch
cd ferretdb-klutch
git init

Step 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 port
EXPOSE 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 it

Note: 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)

  1. Follow the PostgreSQL deployment guide to create a PostgreSQL instance on Klutch.sh
  2. Note the connection details (host, port, username, password, database name)
  3. 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 backend
ENV FERRETDB_HANDLER=sqlite
ENV FERRETDB_SQLITE_URL=file:/state/
EXPOSE 27017
# Create directory for SQLite data
RUN mkdir -p /state

For 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 2
done
echo "PostgreSQL is ready - starting FerretDB"
# Start FerretDB
exec /ferretdb

Update your Dockerfile to use the custom entrypoint:

FROM ghcr.io/ferretdb/ferretdb:latest
# Install PostgreSQL client tools (for pg_isready)
USER root
RUN apk add --no-cache postgresql-client
# Copy custom entrypoint
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 27017
USER ferretdb
ENTRYPOINT ["/entrypoint.sh"]

Step 5: Test Locally (Optional)

Before deploying to Klutch.sh, you can test your FerretDB setup locally. First, start a PostgreSQL container:

Terminal window
# Start PostgreSQL for testing
docker 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 ready
sleep 5
# Build the FerretDB Docker image
docker build -t my-ferretdb .
# Run FerretDB container
docker 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 done
docker stop ferretdb-test postgres-test
docker rm ferretdb-test postgres-test

Step 6: Push to GitHub

Commit your Dockerfile and any configuration files to your GitHub repository:

Terminal window
git add Dockerfile entrypoint.sh
git commit -m "Add FerretDB Dockerfile and configuration"
git remote add origin https://github.com/yourusername/ferretdb-klutch.git
git push -u origin main

Connecting 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/mydatabase

With Authentication (if configured in PostgreSQL):

mongodb://username:password@example-app.klutch.sh:8000/mydatabase?authMechanism=PLAIN

Replace:

  • example-app.klutch.sh with your actual Klutch.sh app URL
  • mydatabase with your database name
  • username and password with 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 schema
const 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 user
async 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 MongoClient
from datetime import datetime
# Connect to FerretDB
uri = "mongodb://example-app.klutch.sh:8000/myapp"
client = MongoClient(uri)
# Access database and collection
db = client.myapp
users = db.users
# Insert a document
result = users.insert_one({
'name': 'Alice Johnson',
'email': 'alice@example.com',
'age': 25,
'createdAt': datetime.now()
})
print(f'Inserted document ID: {result.inserted_id}')
# Query documents
all_users = list(users.find())
for user in all_users:
print(f"User: {user['name']}, Email: {user['email']}")
# Update a document
users.update_one(
{'name': 'Alice Johnson'},
{'$set': {'age': 26}}
)
# Find one document
user = users.find_one({'name': 'Alice Johnson'})
print(f'Updated user: {user}')
# Close connection
client.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):

<?php
require '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

    1. 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
    2. Log in to Klutch.sh

      Navigate to klutch.sh/app and sign in to your account.

    3. Create a New Project

      Go to Create Project and give your project a meaningful name (e.g., “FerretDB Proxy”).

    4. Create a New App

      Navigate to Create App and configure the following settings:

    5. Select Your Repository

      • Choose GitHub as your Git source
      • Select the repository containing your Dockerfile
      • Choose the branch you want to deploy (usually main or master)
    6. 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)
    7. 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

      Optional:

      • FERRETDB_TELEMETRY: Set to disable to opt out of anonymous telemetry (default: enabled)
      • FERRETDB_HANDLER: Database handler type, set to pg for PostgreSQL (default: pg)
      • FERRETDB_MODE: Operation mode - normal, proxy, or diff-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/ferretdb
      FERRETDB_TELEMETRY=disable

      Security Note: Keep your PostgreSQL credentials secure. Never commit them to your repository.

    8. 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
    9. 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)
    10. 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
    11. 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 commands
      db.test.insertOne({message: "Hello FerretDB"})
      db.test.find()
    12. Access Your Database

      Your FerretDB instance is now accessible at:

      mongodb://example-app.klutch.sh:8000/mydatabase

      Use 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:

Terminal window
# Backup PostgreSQL database
pg_dump -h postgres-app.klutch.sh -p 8000 -U ferretdb -d ferretdb > backup.sql
# Restore from backup
psql -h postgres-app.klutch.sh -p 8000 -U ferretdb -d ferretdb < backup.sql

Backup 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 collection
db.users.insertOne({ _id: 1, name: "John Doe", email: "john@example.com" });
// Orders collection with reference
db.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 info
db.runCommand({ buildInfo: 1 })
// Server status
db.runCommand({ serverStatus: 1 })
// Database statistics
db.stats()
// Collection statistics
db.myCollection.stats()

PostgreSQL Monitoring:

-- Check active connections
SELECT count(*) FROM pg_stat_activity;
-- Check database size
SELECT pg_size_pretty(pg_database_size('ferretdb'));
-- Check table sizes
SELECT schemaname, tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
LIMIT 10;
-- Check slow queries (if pg_stat_statements is enabled)
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;

MongoDB Compatibility

FerretDB implements a subset of MongoDB features. Here’s what’s supported:

Supported Operations

CRUD Operations:

  • insertOne, insertMany
  • findOne, find with basic queries
  • updateOne, updateMany
  • deleteOne, deleteMany
  • countDocuments, 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_URL environment 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=PLAIN in 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:

  1. Navigate to your app in the Klutch.sh dashboard
  2. Go to the “Logs” section
  3. Look for error messages or warnings
  4. Common issues include PostgreSQL connection problems or unsupported operations

Checking PostgreSQL Backend

Connect directly to PostgreSQL to verify data storage:

Terminal window
# Connect to PostgreSQL
psql -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 table
SELECT * FROM myapp.users_<uuid>;
# Exit
\q

Advanced Configuration

Custom FerretDB Modes

FerretDB supports different operation modes:

Normal Mode (default):

ENV FERRETDB_MODE=normal

Standard operation mode for production use.

Proxy Mode:

ENV FERRETDB_MODE=proxy

Passes unsupported operations through to PostgreSQL (experimental).

Diff Mode:

ENV FERRETDB_MODE=diff-normal

Compares FerretDB results with actual MongoDB (for testing compatibility).

Debug and Logging

Enable debug logging for troubleshooting:

ENV FERRETDB_DEBUG_ADDR=:8088

This 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=sqlite
ENV FERRETDB_SQLITE_URL=file:/state/
EXPOSE 27017
RUN mkdir -p /state

Note: SQLite backend is suitable for development/testing only, not production.

Migration from MongoDB

If migrating from MongoDB to FerretDB:

  1. Export MongoDB data:
Terminal window
mongodump --uri="mongodb://old-mongodb:27017/mydb" --out=/backup
  1. Import into FerretDB:
Terminal window
mongorestore --uri="mongodb://example-app.klutch.sh:8000/mydb" /backup
  1. Verify data:
Terminal window
# Count documents in each collection
mongosh "mongodb://example-app.klutch.sh:8000/mydb" --eval "db.getCollectionNames().forEach(c => print(c + ': ' + db[c].countDocuments()))"
  1. Update application connection string to point to FerretDB

  2. 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


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.