What happened
You wired up multi-document transaction support, ran the app locally, and got slapped with this:
MongoServerError: Transaction numbers are only allowed on a replica set member or mongos
Nine times out of ten it shows up in a local dev environment. MongoDB is running as a plain standalone mongod โ the default when you install via a package manager or start it with no config file. Transactions need either a replica set or a sharded cluster (mongos). Standalone mode simply doesn't support them, full stop.
Confirming the root cause
Check what mode your instance is actually running before touching anything:
mongosh --eval "db.adminCommand({ isMaster: 1 })"
No "setName" field in the output? You're on a standalone node. That's your culprit.
{
"ismaster": true,
"maxBsonObjectSize": 16777216,
...
// No "setName" field = standalone mode
}
A replica set member looks different โ it always carries the set name:
{
"setName": "rs0",
"ismaster": true,
...
}
Note: On MongoDB 5.0+, isMaster is deprecated. Use db.adminCommand({ hello: 1 }) instead โ same output structure, just the preferred command going forward.
The fix: convert standalone to a single-node replica set
You don't need three nodes for local dev. A single-node replica set unlocks full transaction support with essentially zero overhead. There are three ways to get there depending on your setup.
Option 1 โ Edit mongod.conf (recommended)
Find your config file โ typically /etc/mongod.conf on Linux or /usr/local/etc/mongod.conf on macOS with Homebrew. Add the replication block:
# /etc/mongod.conf
replication:
replSetName: "rs0"
Restart the service:
# Linux (systemd)
sudo systemctl restart mongod
# macOS (Homebrew)
brew services restart mongodb-community
Then kick off replica set initiation โ this is a one-time step:
mongosh --eval "rs.initiate()"
You should see:
{ "ok": 1 }
Option 2 โ Command-line flag (quick smoke test)
Starting mongod manually without a config file? Pass the flag directly:
mongod --replSet rs0 --dbpath /data/db
Open a second terminal and initiate the set once:
mongosh --eval "rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: 'localhost:27017' }] })"
Option 3 โ Docker Compose
The tricky part with containers is that rs.initiate() has to run after MongoDB is healthy. An init container handles that cleanly:
services:
mongo:
image: mongo:7
command: ["--replSet", "rs0", "--bind_ip_all"]
ports:
- "27017:27017"
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
mongo-init:
image: mongo:7
depends_on:
mongo:
condition: service_healthy
restart: "no"
entrypoint: >
mongosh --host mongo:27017 --eval
"rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: 'mongo:27017' }] })"
docker compose up -d
Verify the fix
Pull up the replica set status:
mongosh --eval "rs.status()"
Find "stateStr" : "PRIMARY" in the members array. Good. Now run a transaction directly to confirm it works end-to-end:
// Quick smoke test in mongosh
const session = db.getMongo().startSession();
session.startTransaction();
try {
session.getDatabase('test').orders.insertOne({ item: 'test' }, { session });
session.commitTransaction();
print('Transaction committed OK');
} catch (e) {
session.abortTransaction();
print('Transaction failed:', e.message);
} finally {
session.endSession();
}
Transaction committed OK? You're done.
Update your connection string
Once you switch to replica set mode, add the replica set name to your connection string. Skip this and some drivers won't enable transaction support even when talking to a replica set โ it's a frustrating gotcha.
# Before
mongodb://localhost:27017/mydb
# After
mongodb://localhost:27017/mydb?replicaSet=rs0
Node.js with Mongoose:
await mongoose.connect('mongodb://localhost:27017/mydb?replicaSet=rs0');
Python with PyMongo:
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/mydb?replicaSet=rs0')
What about production?
Hitting this in production means your deployment is running standalone MongoDB โ no automatic failover, no data redundancy. Fix that regardless of transactions. A proper 3-node replica set is the baseline for any production workload. Most managed services (Atlas, MongoDB on DigitalOcean, etc.) provision replica sets by default, so this is really a self-hosted concern. The MongoDB replica set deployment guide covers the full setup.
Lessons learned
- MongoDB transactions have required a replica set since version 4.0 โ this is a hard architectural constraint, not a config toggle.
- Running a single-node replica set in dev costs you nothing and prevents this exact surprise when code hits staging.
- Always add
?replicaSet=rs0to local connection strings after making this change โ it avoids confusing driver behavior around transaction discovery. - In CI with bare
mongod, the Docker Compose init-container pattern is the most reliable way to handle the one-timers.initiate()call without race conditions.

