How MongoDB Data Balancing Works and How to Configure It Using Docker Compose

MongoDB's balancer is a background process that runs on the mongos router to automatically migrate chunks between shards, ensuring even data distribution, and you can configure it via the config.settings collection or helper methods like sh.startBalancer() and sh.setChunkSize().

MongoDB uses a sharded cluster architecture to distribute data across multiple replica sets, relying on an automated data balancing mechanism to maintain performance as datasets grow. This guide explains how the balancer manages chunk migrations and how to configure it using the minhhungit/mongodb-cluster-docker-compose repository, which provides a complete Docker Compose setup for running a sharded MongoDB cluster locally.

What Is the MongoDB Balancer and How It Works

The balancer is responsible for maintaining equilibrium across a sharded cluster by moving chunks—contiguous ranges of shard key values—from shards with more data to those with less.

Chunk-Based Data Distribution

MongoDB partitions data into chunks based on the shard key. When a chunk grows beyond the chunkSize threshold (default 64 MiB), the config server marks it for splitting. The balancer then evaluates the distribution across all shards and initiates migrations if it detects an imbalance.

The Balancer Process on Mongos

According to the repository's README, the balancer runs as a background process on the mongos router. The sample sh.status() output shows:


balancer:
  Currently enabled:  yes
  Currently running:  no
  No recent migrations

This indicates the balancer is enabled by default but idle when the cluster is balanced. The status output is documented in the README around lines 171‑174 of readme.md.

Core Components of the Sharded Cluster

The data balancing mechanism relies on three architectural components defined in the repository's docker-compose.yml and startup scripts.

Config Servers Store Metadata

The config servers maintain the cluster's metadata, including chunk ranges and balancer settings. In docker-compose.yml, three config-server containers (e.g., mongo-config-01) are defined to provide redundancy for this critical metadata.

Mongos Router Runs the Balancer

The mongos process acts as the query router and hosts the balancer logic. The scripts/entrypoint-route.sh script starts the mongos instance and waits for config servers and shards to become available before executing sh.addShard() commands to register shards with the cluster.

Shard Replica Sets Hold Data

Data is stored in shard replica sets. Each shard is started by an entrypoint-shardXX.sh script (e.g., scripts/entrypoint-shard01.sh) that initiates the replica set via the init_shard() function before joining the cluster.

How to Check Balancer Status

To inspect the current balancing state in the Docker environment, execute mongosh on the router container:

docker exec -it router-01 mongosh --port 27017 <<'EOF'
sh.status()
EOF

Look for the balancer: section in the output. It reports whether the balancer is enabled, whether it is actively running, and statistics on recent chunk migrations.

Configuring the Data Balancing Mechanism

MongoDB exposes balancer controls through the config.settings collection in the admin database. All configuration commands must run against the mongos router.

Enable or Disable the Balancer

Use the helper methods to toggle the balancer state:

// Disable automatic balancing
sh.stopBalancer();

// Re-enable automatic balancing
sh.startBalancer();

These commands update the balancerEnabled field in config.settings. Verify the change with:

db.getSiblingDB("config").settings.find({_id: "balancer"}).pretty();

Adjust Chunk Size

The default chunkSize is 64 MiB. Increase or decrease it to control the granularity of data distribution:

// Set chunk size to 128 MiB
sh.setChunkSize(128);

Smaller chunks enable more even distribution but increase metadata overhead on config servers. Larger chunks reduce migration frequency but may create hot spots on individual shards.

Set a Balancing Window

Restrict balancing operations to off-peak hours by defining an activeWindow:

db.getSiblingDB("config").settings.update(
   { _id: "balancer" },
   { $set: { 
       activeWindow: { start: "03:00", stop: "05:00" }   // 3 am-5 am UTC
   } },
   { upsert: true }
);

During hours outside this window, the balancer will not initiate new chunk migrations.

Force Manual Balancing

To trigger an immediate balancing round without waiting for the background process:

sh.startBalancer();
sh.balance();   // Forces an immediate balancing round

Disable Auto-Splitting

For testing or specific maintenance scenarios, prevent automatic chunk splitting:

db.getSiblingDB("config").settings.update(
   { _id: "autosplit" },
   { $set: { enabled: false } },
   { upsert: true }
);

Complete Configuration Example

Below is a self-contained script you can execute inside the router-01 container to tune the balancer for a production-like environment. Save this as scripts/balance-config.sh in your repository:

#!/bin/bash

# router-balancer-config.sh – run inside router-01

mongosh --port 27017 <<'EOS'
print("Current balancer status:");
sh.status().balancer

// Enable the balancer (if it was disabled)
sh.startBalancer();

// Set chunk size to 128 MiB (default is 64 MiB)
sh.setChunkSize(128);

// Restrict balancing to a nightly window (02:00-04:00 UTC)
db.getSiblingDB("config").settings.update(
  { _id: "balancer" },
  { $set: { activeWindow: { start: "02:00", stop: "04:00" } } },
  { upsert: true }
);

print("Updated balancer configuration:");
db.getSiblingDB("config").settings.find({_id:"balancer"}).pretty();
EOS

Invoke the script after the cluster has started:

docker exec -it router-01 bash /scripts/balance-config.sh

Where to Find the Relevant Code in the Repository

The minhhungit/mongodb-cluster-docker-compose repository implements the sharded cluster architecture that supports the data balancing mechanism described above.

File Purpose
docker-compose.yml Declares the router, config servers, and shard containers that make up the cluster.
scripts/entrypoint-route.sh Starts mongos, waits for config servers and shards, then executes sh.addShard() commands.
scripts/entrypoint-shard01.sh Boots the first shard's mongod instance and initiates the replica set via the init_shard() function.
readme.md Contains sample sh.status() output showing the balancer block and cluster verification steps.
scripts/init-router.js Holds the JavaScript commands that register shards with the cluster metadata.

Browse these files directly on GitHub:

Summary

  • The MongoDB balancer is a background process running on the mongos router that migrates chunks (ranges of shard key values) between shards to maintain even data distribution.
  • Configuration is managed through the config.settings collection using helpers like sh.startBalancer(), sh.stopBalancer(), and sh.setChunkSize(), or by setting an activeWindow for time-based restrictions.
  • The minhhungit/mongodb-cluster-docker-compose repository provides the Docker infrastructure—defined in docker-compose.yml and managed by entrypoint-route.sh—that implements the config servers, mongos router, and shard replica sets required for automatic balancing.
  • You can inspect balancer status with sh.status(), force immediate balancing with sh.balance(), and tune performance by adjusting the chunkSize default of 64 MiB.

Frequently Asked Questions

How do I know if the MongoDB balancer is actually running?

Connect to the mongos router and run sh.status(). The output includes a balancer: section that reports Currently enabled and Currently running status. In the minhhungit/mongodb-cluster-docker-compose repository, the README shows sample output indicating the balancer is enabled by default but may display Currently running: no when the cluster is already balanced or when no migrations are needed.

What is the default chunk size, and when should I change it?

The default chunkSize is 64 MiB. You should increase it (using sh.setChunkSize()) if you have a very large dataset and want to reduce the overhead of frequent migrations and metadata tracking. Decrease it if you need finer-grained distribution to avoid hot spots on individual shards, though this increases the storage and processing load on the config servers.

Can I schedule MongoDB balancing to run only during off-peak hours?

Yes. You can define an activeWindow in the config.settings collection to restrict the balancer to specific UTC times. For example, setting activeWindow: { start: "02:00", stop: "04:00" } ensures the balancer only migrates chunks between 2 am and 4 am UTC, preventing balancing operations from impacting peak-hour workloads.

Where is the balancer process located in the Docker Compose architecture?

In the minhhungit/mongodb-cluster-docker-compose setup, the balancer runs as part of the mongos router process defined in docker-compose.yml and started by scripts/entrypoint-route.sh. You must connect to the router container (e.g., router-01) to inspect or configure balancer settings, as the shard containers only run mongod instances and do not execute balancing logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →