Dropping an index in MongoDB is one command:
db.orders.dropIndex("status_1")
The command is trivial. The judgment is not: dropping the wrong index turns a fast query back into a collection scan. So the real skill here is confirming an index is dead weight before you remove it. Let us do the safe version.
First, see what you have
You cannot drop an index by name if you do not know the name. List them:
db.orders.getIndexes()
[
{ v: 2, key: { _id: 1 }, name: "_id_" },
{ v: 2, key: { userId: 1, status: 1 }, name: "userId_1_status_1" },
{ v: 2, key: { legacyField: 1 }, name: "legacyField_1" }
]
Now you can drop by name, or by the key document, whichever you find clearer:
db.orders.dropIndex("legacyField_1")
db.orders.dropIndex({ legacyField: 1 }) // same index, by key
Measure it before changing it
This is the step people skip, and then page someone at 2am. Before dropping, ask MongoDB how often the index has been used since the server started:
db.orders.aggregate([{ $indexStats: {} }])
{ name: "userId_1_status_1", accesses: { ops: 91043 } } // busy, keep it
{ name: "legacyField_1", accesses: { ops: 0, since: ... } } // candidate to investigate
ops: 0 is not global proof that an index is unused. The counter applies only to the node where the query runs,
starts at accesses.since, and resets after a server restart or index modification. Check every replica-set member
and cover a representative traffic cycle, including nightly or monthly work. The
$indexStats reference defines
that evidence boundary.
Hide before you drop
MongoDB recommends hiding an index before permanent removal. Hidden indexes are unavailable to the query planner, but MongoDB keeps them maintained, preserves unique and TTL behavior, and can restore them immediately without a rebuild:
db.orders.hideIndex("legacyField_1")
// observe the real workload and plans
db.orders.unhideIndex("legacyField_1") // immediate recovery when a query regresses
Hidden indexes still cost disk, memory, and write maintenance, and changing visibility resets that index's usage counter. Once the representative workload stays healthy, the permanent drop becomes a much better-supported decision.
The one you cannot drop
dropIndexes() (plural) removes every index on the collection at once, except the _id index, which is required and refuses to leave:
db.orders.dropIndexes() // everything except _id_
Handy for a collection you are rebuilding from scratch, alarming everywhere else. The _id index is load-bearing, so MongoDB will not let you drop it. That is one guardrail you do not have to think about.
Why bother dropping indexes at all
Because every index you keep is a tax on every write. An insert has to update each index; an unused one costs that work forever and gives nothing back, plus the storage and memory it holds. Dropping the freeloaders is not cleanup for its own sake, it is a direct win on write throughput and disk. The full version of this loop, measure usage then prune, is MongoDB index optimization, and if you are adding indexes rather than removing them, start with how to create an index.
mongoui shows the whole index budget in one view: node-local usage with its observation start, conservative prefix overlap, planner visibility, and storage. A reviewed Hide action records the change locally, Restore makes the index available without rebuilding, and permanent Drop remains a separate typed-name decision. Keep the indexes your workload uses; retire the rest with evidence and a recovery path.
