MongoDB storage grows and does not shrink when you delete. That surprises people, and it is the root of most "where did my disk go" questions. Forty gigabytes of "we will clean that up later" is just your storage bill writing a memoir. The fix is understanding what the numbers mean, finding the collection carrying the weight, and reclaiming the space without taking the database down to do it.
storageSize is not the same as your data
Ask a collection for its stats and read two numbers:
db.orders.stats()
{
count: 1240000,
size: 3221225472, // ~3 GB of live documents (logical)
storageSize: 9663676416, // ~9 GB allocated on disk
totalIndexSize: 1073741824
}
size is the logical, uncompressed size of the documents that are actually there. storageSize is what WiredTiger has allocated on disk for them, after compression and including blocks that were freed by deletes but not handed back to the operating system. When storageSize towers over size after a big cleanup, that gap is your reclaimable space. The collStats reference documents every field.
Find the collection that is mostly dead weight
Storage climbs and nobody is sure why. The usual answer is one collection holding the bulk of it, and most of that being documents nobody reads anymore: old events, soft-deleted records, a logging collection that was supposed to be temporary in 2021. Walk the collections and compare their storageSize:
db.getCollectionNames().forEach(name => {
const s = db[name].stats()
print(name, (s.storageSize / 1024 / 1024).toFixed(0) + " MB")
})
The reclaimable space is usually hiding in plain sight, in one collection you forgot was still growing. Once you find it, the question is how to delete the dead records (see removing documents safely) and then how to hand the space back.
Reclaim it with compact, safely
Deleting documents frees the space for reuse inside the collection, but the on-disk file does not shrink on its own. To return the space to the operating system, run compact:
db.runCommand({ compact: "orders" })
Two things to know before you run it. Compact blocks operations on that collection while it runs, so it is not a "do it on the primary at noon" command. On a replica set, run it on each secondary one at a time, then step the primary down and compact the former primary, so the collection is always available on some member. The compact reference covers the exact behavior for your MongoDB version.
Indexes take storage too, so while you are here, prune the ones nothing uses. That is MongoDB index optimization, and it often reclaims more than the documents did.
Or see reclaimable space at a glance
mongoui's Index and Storage insight shows where storage actually goes, collection by collection, with reclaimable space called out. It reads the same stats() numbers for every collection and surfaces the gap between logical data and allocated disk, so the collection that is mostly dead weight shows up without a script.
Every read is local: the engine runs on your machine and talks straight to your database, so your storage and collection data never leave your network. Find the heavy collection, clear the dead records behind a dry run, compact on a schedule that keeps the database up, and run the scan before your storage bill files for its own line item.