TechEarl

How to Run MongoDB in Docker (With Persistent Storage)

MongoDB in a container with a named volume on /data/db so your collections survive restarts, an admin user from MONGO_INITDB_ROOT_*, and the replica-set caveat for transactions.

Ishan KarunaratneIshan Karunaratne⏱️ 5 min readUpdated
Share thisCopied

MongoDB in Docker is the same shape as the other databases: one docker run with the right env vars, a named volume on /data/db, and a port mapping if you want to connect from outside. Two things that catch people: the admin-user env vars only fire on first init, and transactions require a replica set even for a single-node setup.

How do I run MongoDB in Docker?

bash
docker run -d --name mongo \
  -e MONGO_INITDB_ROOT_USERNAME=root \
  -e MONGO_INITDB_ROOT_PASSWORD=change-me \
  -p 27017:27017 \
  -v mongo-data:/data/db \
  mongo:7

MongoDB 7 in the background, with a root user created on first init, port 27017 published, and a named volume keeping the data alive across container removal.

Try it with your own values

Configure version, credentials, port, and volume.

Pick a version

  • mongo:7 — MongoDB 7, current GA at time of writing. Default for new projects.
  • mongo:6 — MongoDB 6, still supported.
  • mongo:5 — older, supported only on specific platforms; check the registry tag list before pinning.

Mongo 7 requires CPU features (AVX) that some older or budget cloud VMs lack — the container fails to start with an illegal instruction. On those hosts, run mongo:5 or upgrade the host.

The basic run command

bash
docker run -d --name :container_name \
  -e MONGO_INITDB_ROOT_USERNAME=:user \
  -e MONGO_INITDB_ROOT_PASSWORD=:password \
  -p :host_port:27017 \
  -v :volume:/data/db \
  mongo::mongo_version

MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD create an admin user on first init. They are only honored on the first run, when the data directory is empty. If you point the container at an existing volume, those vars are silently ignored.

Without MONGO_INITDB_ROOT_*, MongoDB starts without authentication enabled. Fine for local dev, dangerous if the port is exposed to a network.

Why mount /data/db

Same pattern as the other databases: the data directory inside the container is at /data/db. Without a volume mounted there, all collections live in the container's writable layer and die with docker rm. The named volume makes that data persist independently.

bash
docker stop :container_name && docker rm :container_name

docker run -d --name :container_name \
  -e MONGO_INITDB_ROOT_USERNAME=:user \
  -e MONGO_INITDB_ROOT_PASSWORD=:password \
  -p :host_port:27017 \
  -v :volume:/data/db \
  mongo::mongo_version
# Your data is still there.

Practical usage: connecting

With mongosh inside the container:

bash
docker exec -it :container_name \
  mongosh -u :user -p :password --authenticationDatabase admin

From the host (with mongosh installed):

bash
mongosh "mongodb://:user::password@127.0.0.1::host_port/?authSource=admin"

Connection string for an app:

code
mongodb://:user::password@127.0.0.1::host_port/myapp?authSource=admin

authSource=admin is the key bit — without it, MongoDB tries to authenticate against the database name in the URL path, which fails for a root user.

Replica set for transactions

Multi-document transactions in MongoDB require a replica set, even if it has only one member. A single standalone container won't let you start a transaction at all.

bash
docker run -d --name :container_name \
  -p :host_port:27017 \
  -v :volume:/data/db \
  mongo::mongo_version \
  --replSet rs0

# Initiate the replica set once
docker exec -it :container_name mongosh --eval 'rs.initiate()'

Without --replSet rs0, you'll get Transaction numbers are only allowed on a replica set member from your driver. For local dev that exercises transactions, single-node replica sets are the standard pattern.

Compose version

yaml
services:
  mongo:
    image: mongo::mongo_version
    environment:
      MONGO_INITDB_ROOT_USERNAME: :user
      MONGO_INITDB_ROOT_PASSWORD: :password
    ports:
      - "::host_port:27017"
    volumes:
      - :volume:/data/db
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.runCommand({ ping: 1 })"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  :volume:

Backups

bash
# Logical dump of every database
docker exec :container_name mongodump --uri "mongodb://:user::password@127.0.0.1:27017/?authSource=admin" --out /dump
docker cp :container_name:/dump ./mongo-backup-$(date +%Y%m%d)

# Restore
docker cp ./mongo-backup-20260601 :container_name:/dump
docker exec :container_name mongorestore --uri "mongodb://:user::password@127.0.0.1:27017/?authSource=admin" /dump

Common pitfalls

  • Init env vars ignored after first run. MONGO_INITDB_ROOT_USERNAME and friends fire only on an empty data directory. Create users via mongosh after init if you need new ones.
  • Illegal instruction on older CPUs. Mongo 7 requires AVX. Downgrade to mongo:5 or move to a host with newer instructions.
  • Transactions failing with "only allowed on a replica set." Add --replSet rs0 to the command and rs.initiate() once.
  • Auth failing with valid credentials. Almost always missing authSource=admin. The root user is in the admin database, not the database you're connecting to.
  • No password and port published. Always set the root user or restrict the port to loopback (-p 127.0.0.1:27017:27017).

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsDockerMongoDBNoSQLDatabasePersistenceDevOps

Found this useful? Pass it on.

Copied
Ishan Karunaratne

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts