Running MongoDB in Docker simplifies deployment and makes environments reproducible across development, testing and production. You can spin up a database in seconds without dealing with complex installation procedures. This guide covers everything from basic container setup to production configurations with replica sets, persistence, custom settings and proper backup strategies.
Why run MongoDB in Docker
Traditional MongoDB installation requires adding repositories, managing versions, and cleaning up when things break. Docker containers provide isolation and consistency that native installations struggle to match.
Benefits of containerized MongoDB
Docker containers bundle MongoDB with all dependencies into a single package. You get identical behavior on your laptop, CI pipeline, and production servers. The classic "works on my machine" problem disappears.
Containers start fast. Launching a fresh MongoDB instance takes about 5-10 seconds versus several minutes for traditional installation. This matters for integration tests and rapid development cycles.
Cleanup is simple. Delete the container and it's gone completely. No leftover config files, no orphaned data directories cluttering your system.
When Docker makes sense for MongoDB
Docker works well for development environments where quick setup and teardown matters. It's also solid for microservices architectures where each service might need its own database instance. CI/CD pipelines benefit significantly from reproducible database containers.
For production use, Docker adds a bit of complexity but provides consistency across environments. The performance overhead is typically 1-3% for database workloads, which most applications can easily absorb.
Quick start with Docker run
The fastest way to get MongoDB running is a single Docker command. This approach works for testing and development scenarios.
Basic container setup
Start MongoDB with minimal configuration:
docker run -d \
--name mongodb \
mongo:8
This starts MongoDB 8 in detached mode. The container runs until you stop it explicitly.
Check if it's running:
docker ps
Connect to the database:
docker exec -it mongodb mongosh
Environment variables for initial setup
MongoDB's Docker image supports environment variables for first-run configuration:
| Variable | Description | Required |
|---|---|---|
MONGO_INITDB_ROOT_USERNAME |
Admin username | Optional |
MONGO_INITDB_ROOT_PASSWORD |
Admin password | Optional |
MONGO_INITDB_DATABASE |
Initial database name | Optional |
Create an admin user on startup:
docker run -d \
--name mongodb \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=secretpassword \
mongo:8
Connect with authentication:
docker exec -it mongodb mongosh -u admin -p secretpassword --authenticationDatabase admin
Exposing ports
MongoDB runs on port 27017 inside the container by default. Map it to your host:
docker run -d \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=secretpassword \
mongo:8
Now you can connect from your host machine:
mongosh "mongodb://admin:secretpassword@127.0.0.1:27017/admin"
Use a different host port if 27017 is already in use:
docker run -d \
--name mongodb \
-p 27018:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=secretpassword \
mongo:8
Data persistence with volumes
Without volumes, your data vanishes when the container stops. That's acceptable for throwaway test databases, but anything beyond that needs persistence.
Named volumes
Docker named volumes are the simplest approach:
docker run -d \
--name mongodb \
-v mongodb-data:/data/db \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=secretpassword \
mongo:8
The volume mongodb-data persists even after you delete the container. List your volumes:
docker volume ls
Inspect volume details:
docker volume inspect mongodb-data
Bind mounts
Bind mounts map a host directory directly into the container. This is useful when you need direct access to data files:
docker run -d \
--name mongodb \
-v /path/to/data:/data/db \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=secretpassword \
mongo:8
Make sure the directory exists and has proper permissions. On Linux, the MongoDB user inside the container needs write access:
mkdir -p /path/to/data
chown -R 999:999 /path/to/data
The UID 999 corresponds to the MongoDB user inside the container.
Volume backup
Back up a named volume by running a temporary container:
docker run --rm \
-v mongodb-data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/mongodb-backup.tar.gz -C /source .
This creates a compressed archive of the data directory. For proper database backups, use mongodump instead, which we'll cover later.
Docker Compose for MongoDB
Docker Compose makes multi-container setups manageable and keeps configurations under version control.
Basic compose file
Create a docker-compose.yml:
services:
mongodb:
image: mongo:8
container_name: mongodb
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secretpassword
MONGO_INITDB_DATABASE: myapp
ports:
- "27017:27017"
volumes:
- mongodb-data:/data/db
restart: unless-stopped
volumes:
mongodb-data:
Start the service:
docker compose up -d
Stop and remove:
docker compose down
Remove including volumes:
docker compose down -v
Application with MongoDB
A typical setup includes your application and MongoDB together:
services:
app:
build: .
environment:
MONGODB_URI: mongodb://appuser:apppassword@mongodb:27017/myapp?authSource=admin
depends_on:
mongodb:
condition: service_healthy
ports:
- "8080:8080"
mongodb:
image: mongo:8
container_name: mongodb
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secretpassword
volumes:
- mongodb-data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped
volumes:
mongodb-data:
The depends_on with condition: service_healthy ensures your application waits for MongoDB to be ready before starting.
Custom configuration
Default settings work for development but production workloads often need tuning.
Configuration file mount
Create a custom configuration file mongod.conf:
storage:
dbPath: /data/db
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 2
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
net:
port: 27017
bindIp: 0.0.0.0
security:
authorization: enabled
operationProfiling:
slowOpThresholdMs: 100
mode: slowOp
Mount it into the container:
docker run -d \
--name mongodb \
-v ./mongod.conf:/etc/mongod.conf:ro \
-v mongodb-data:/data/db \
-v mongodb-logs:/var/log/mongodb \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=secretpassword \
mongo:8 --config /etc/mongod.conf
Docker Compose with custom config
services:
mongodb:
image: mongo:8
container_name: mongodb
command: ["--config", "/etc/mongod.conf"]
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secretpassword
volumes:
- mongodb-data:/data/db
- mongodb-logs:/var/log/mongodb
- ./mongod.conf:/etc/mongod.conf:ro
ports:
- "27017:27017"
restart: unless-stopped
volumes:
mongodb-data:
mongodb-logs:
Common configuration options
Key settings to consider for production:
| Setting | Default | Production recommendation |
|---|---|---|
storage.wiredTiger.engineConfig.cacheSizeGB |
50% of RAM - 1GB | Set explicitly based on available memory |
operationProfiling.slowOpThresholdMs |
100 | Tune based on your performance requirements |
net.maxIncomingConnections |
65536 | Set based on expected concurrent connections |
security.authorization |
disabled | Always enable in production |
Verify your configuration is applied:
docker exec mongodb mongosh -u admin -p secretpassword --authenticationDatabase admin --eval "db.adminCommand({getParameter: '*'})"
Initialization scripts
The MongoDB Docker image can run scripts on first startup. This is useful for creating users, collections, and seed data.
JavaScript initialization
Place .js or .sh files in /docker-entrypoint-initdb.d/:
Create init/01-create-users.js:
db = db.getSiblingDB('myapp');
db.createUser({
user: 'appuser',
pwd: 'apppassword',
roles: [
{ role: 'readWrite', db: 'myapp' }
]
});
db.createUser({
user: 'readonly',
pwd: 'readonlypassword',
roles: [
{ role: 'read', db: 'myapp' }
]
});
Create init/02-create-collections.js:
db = db.getSiblingDB('myapp');
db.createCollection('users', {
validator: {
$jsonSchema: {
bsonType: 'object',
required: ['email', 'createdAt'],
properties: {
email: {
bsonType: 'string',
description: 'must be a string and is required'
},
createdAt: {
bsonType: 'date',
description: 'must be a date and is required'
}
}
}
}
});
db.users.createIndex({ email: 1 }, { unique: true });
Mount the init directory:
services:
mongodb:
image: mongo:8
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secretpassword
volumes:
- mongodb-data:/data/db
- ./init:/docker-entrypoint-initdb.d:ro
restart: unless-stopped
volumes:
mongodb-data:
Scripts run in alphabetical order, only on first container start when the data directory is empty.
Shell script initialization
For more complex setup, use shell scripts:
Create init/00-setup.sh:
#!/bin/bash
set -e
mongosh <<EOF
use admin
db.auth('$MONGO_INITDB_ROOT_USERNAME', '$MONGO_INITDB_ROOT_PASSWORD')
use myapp
db.createCollection('config')
db.config.insertOne({
key: 'version',
value: '1.0.0',
createdAt: new Date()
})
EOF
Make it executable:
chmod +x init/00-setup.sh
Networking
Docker networking controls how containers communicate with each other and the outside world.
Default bridge network
Containers on the default bridge network can communicate via IP address but not hostname. For basic development this works fine:
docker run -d --name mongodb -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=pw mongo:8
docker run -it --rm mongo:8 mongosh "mongodb://admin:pw@$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mongodb):27017/admin"
Custom networks
Custom networks allow hostname-based communication:
docker network create myapp-network
docker run -d \
--name mongodb \
--network myapp-network \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=pw \
mongo:8
docker run -it --rm \
--network myapp-network \
mongo:8 \
mongosh "mongodb://admin:pw@mongodb:27017/admin"
The second container can reach MongoDB using hostname mongodb.
Compose networking
Docker Compose creates a network automatically. Services communicate by service name:
services:
app:
image: myapp
environment:
MONGODB_URI: mongodb://admin:pw@mongodb:27017/myapp?authSource=admin
mongodb:
image: mongo:8
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: pw
Health checks and monitoring
Proper health checks ensure containers are actually ready to serve traffic, not just running.
Basic health check
services:
mongodb:
image: mongo:8
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secretpassword
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
Check health status:
docker inspect --format='{{.State.Health.Status}}' mongodb
Health check with authentication
When authentication is enabled, include credentials in the health check:
healthcheck:
test: ["CMD", "mongosh", "-u", "admin", "-p", "secretpassword", "--authenticationDatabase", "admin", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
Monitoring with logs
View container logs:
docker logs mongodb
Follow logs in real-time:
docker logs -f mongodb
Limit output to recent entries:
docker logs --tail 100 mongodb
Enable profiling in your configuration to catch slow operations:
operationProfiling:
slowOpThresholdMs: 50
mode: slowOp
Mount a volume for logs:
volumes:
- mongodb-data:/data/db
- mongodb-logs:/var/log/mongodb
Backup strategies for Docker MongoDB
Data in containers needs the same backup discipline as traditional installations. Docker adds some considerations but the fundamentals remain.
Using mongodump in Docker
Run mongodump inside the container:
docker exec mongodb mongodump -u admin -p secretpassword --authenticationDatabase admin --out /dump
docker cp mongodb:/dump ./backup
For a specific database:
docker exec mongodb mongodump -u admin -p secretpassword --authenticationDatabase admin --db myapp --out /dump
Compressed backup directly to host:
docker exec mongodb mongodump -u admin -p secretpassword --authenticationDatabase admin --archive --gzip > backup.gz
Scheduled backups with cron
Create a backup script:
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups"
CONTAINER="mongodb"
docker exec $CONTAINER mongodump \
-u admin \
-p "$MONGO_ROOT_PASSWORD" \
--authenticationDatabase admin \
--archive \
--gzip > "$BACKUP_DIR/mongodb_${TIMESTAMP}.gz"
# Keep only last 7 days
find $BACKUP_DIR -name "mongodb_*.gz" -mtime +7 -delete
Add to crontab for daily 3 AM backups:
0 3 * * * /usr/local/bin/mongodb-backup.sh
Using Databasus for automated backups
Manual backup scripts work but require ongoing maintenance and lack built-in monitoring. Databasus (an industry standard for MongoDB backup) provides automated backups with a web interface, scheduling and notifications.
Install Databasus on a separate server using Docker:
docker run -d \
--name databasus \
-p 4005:4005 \
-v ./databasus-data:/databasus-data \
--restart unless-stopped \
databasus/databasus:latest
Or with Docker Compose:
services:
databasus:
image: databasus/databasus:latest
container_name: databasus
ports:
- "4005:4005"
volumes:
- databasus-data:/databasus-data
restart: unless-stopped
volumes:
databasus-data:
Access the web interface at http://your-databasus-server:4005, then:
- Add your database — Click "New Database", select MongoDB, enter your MongoDB server's connection details (host, port, credentials)
- Select storage — Choose local storage, S3, Google Cloud Storage, or other supported destinations
- Select schedule — Set backup frequency: hourly, daily, weekly, or custom cron expression
- Click "Create backup" — Databasus handles backup execution, compression, retention and notifications
Databasus supports multiple notification channels including Slack, Discord, Telegram and email, so you know immediately when backups succeed or fail.
Replica sets in Docker
For production environments, running MongoDB as a replica set provides high availability and data redundancy.
Single-node replica set
Even a single-node replica set is useful because it enables change streams and transactions:
services:
mongodb:
image: mongo:8
container_name: mongodb
command: ["--replSet", "rs0", "--bind_ip_all"]
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secretpassword
ports:
- "27017:27017"
volumes:
- mongodb-data:/data/db
restart: unless-stopped
volumes:
mongodb-data:
Initialize the replica set after starting:
docker exec -it mongodb mongosh -u admin -p secretpassword --authenticationDatabase admin --eval "rs.initiate()"
Three-node replica set
For actual high availability, run three nodes:
services:
mongodb-primary:
image: mongo:8
container_name: mongodb-primary
command: ["--replSet", "rs0", "--bind_ip_all", "--keyFile", "/etc/mongodb/keyfile"]
volumes:
- mongodb-primary-data:/data/db
- ./keyfile:/etc/mongodb/keyfile:ro
networks:
- mongodb-network
restart: unless-stopped
mongodb-secondary1:
image: mongo:8
container_name: mongodb-secondary1
command: ["--replSet", "rs0", "--bind_ip_all", "--keyFile", "/etc/mongodb/keyfile"]
volumes:
- mongodb-secondary1-data:/data/db
- ./keyfile:/etc/mongodb/keyfile:ro
networks:
- mongodb-network
depends_on:
- mongodb-primary
restart: unless-stopped
mongodb-secondary2:
image: mongo:8
container_name: mongodb-secondary2
command: ["--replSet", "rs0", "--bind_ip_all", "--keyFile", "/etc/mongodb/keyfile"]
volumes:
- mongodb-secondary2-data:/data/db
- ./keyfile:/etc/mongodb/keyfile:ro
networks:
- mongodb-network
depends_on:
- mongodb-primary
restart: unless-stopped
networks:
mongodb-network:
volumes:
mongodb-primary-data:
mongodb-secondary1-data:
mongodb-secondary2-data:
Generate the keyfile for internal authentication:
openssl rand -base64 756 > keyfile
chmod 400 keyfile
Initialize the replica set:
docker exec -it mongodb-primary mongosh --eval "
rs.initiate({
_id: 'rs0',
members: [
{ _id: 0, host: 'mongodb-primary:27017', priority: 2 },
{ _id: 1, host: 'mongodb-secondary1:27017', priority: 1 },
{ _id: 2, host: 'mongodb-secondary2:27017', priority: 1 }
]
})
"
Security considerations
Running databases in containers doesn't reduce security requirements. If anything, you need more attention to configuration details.
Enable authentication
Never run MongoDB without authentication in any environment beyond local development:
services:
mongodb:
image: mongo:8
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secretpassword
Secure passwords with secrets
Use environment variables from secrets management:
services:
mongodb:
image: mongo:8
environment:
MONGO_INITDB_ROOT_USERNAME_FILE: /run/secrets/mongo_username
MONGO_INITDB_ROOT_PASSWORD_FILE: /run/secrets/mongo_password
secrets:
- mongo_username
- mongo_password
secrets:
mongo_username:
file: ./secrets/mongo_username.txt
mongo_password:
file: ./secrets/mongo_password.txt
Network isolation
Don't expose database ports to the public internet. Use internal Docker networks:
services:
app:
networks:
- frontend
- backend
mongodb:
networks:
- backend
networks:
frontend:
backend:
internal: true
Resource limits
Prevent runaway containers from consuming all system resources:
services:
mongodb:
image: mongo:8
deploy:
resources:
limits:
cpus: "2"
memory: 4G
reservations:
cpus: "1"
memory: 2G
Production checklist
Before running MongoDB Docker containers in production, verify these items:
- Data persistence configured with volumes
- Authentication enabled with strong passwords
- Custom configuration tuned for workload
- Health checks enabled
- Automated backup strategy in place
- Secrets managed securely (not hardcoded)
- Network properly isolated
- Resource limits set
- Monitoring and alerting configured
- Restart policy set to
unless-stoppedoralways - Container image version pinned (not using
latest)
Troubleshooting common issues
Container exits immediately
Check logs for errors:
docker logs mongodb
Common causes: permission issues on mounted volumes, corrupt data directory, or invalid configuration file syntax.
Permission denied on bind mount
Ensure the host directory has correct ownership:
sudo chown -R 999:999 /path/to/data
Or run MongoDB with your user ID:
docker run -d --user $(id -u):$(id -g) ...
Can't connect from host
Verify port mapping:
docker port mongodb
Check if MongoDB is listening on all interfaces. The default bind address should be 0.0.0.0 in Docker, but verify with:
docker exec mongodb mongosh --eval "db.adminCommand({getCmdLineOpts: 1})"
Replica set won't initialize
Ensure all nodes can resolve each other's hostnames. When using Docker Compose, services communicate by service name. If using custom hostnames, add them to /etc/hosts or use Docker's --add-host option.
Slow performance
Check if WiredTiger cache is sized correctly:
docker exec mongodb mongosh --eval "db.serverStatus().wiredTiger.cache"
For Docker Desktop on macOS and Windows, file system performance through volumes can be slow. Use named volumes instead of bind mounts for better performance.
Conclusion
Running MongoDB in Docker provides consistent environments across development, testing and production. Start with simple docker run commands for quick setups, then move to Docker Compose for more complex configurations. Always configure data persistence with volumes, set up proper health checks, and implement automated backups. The overhead of containerization is minimal compared to the operational benefits of reproducibility and isolation. Pin your image versions, tune your configuration for your workload, and treat container security with the same rigor as traditional deployments.

Top comments (0)