When would you hide a MongoDB index with hidden: true instead of dropping it?
answer
- A rehearsal for a drop, not an optimisation
- The planner ignores it; the storage engine does not
- Undo is instant, rebuild is not
- Constraints and expiry keep working
- hint() on it is an error
basics
~20 sHiding removes an index from the query planner's consideration while keeping it fully maintained, so you can measure the effect of dropping it and undo the change instantly. Dropping a large index is cheap; rebuilding it if you were wrong is not.
solid answer
~40 s`hidden: true` makes the planner ignore an index, so queries behave as if it were gone, while the index itself is still updated on every write and still enforced. That makes it a **safe rehearsal for a drop**: you hide the suspect index, watch latency and plans for a day or two, and if anything regresses you unhide it instantly instead of waiting hours to rebuild it on a large collection. What hiding does *not* do is save you anything on writes — the index is still maintained, so hiding is a diagnostic, not an optimisation. Unique constraints and TTL expiry keep working while hidden. You toggle it with `db.coll.hideIndex("name")` / `unhideIndex("name")` or `collMod`; `_id` cannot be hidden; hidden indexes still appear in `getIndexes()`; and `hint()` on a hidden index errors out.
code
javascript · 4 linesdb.orders.hideIndex("status_1_createdAt_-1")
// observe plans and latency for a full business cycle
db.orders.unhideIndex("status_1_createdAt_-1") // instant rollback
db.orders.dropIndex("status_1_createdAt_-1") // only when confidentgo deeper
Know that an index can be hidden so queries stop using it without deleting it, and that unhiding restores it immediately.
Explain that only planner visibility changes: writes still maintain the index, uniqueness is still enforced, TTL still expires, and hint() on a hidden index errors.
Describe the drop-rehearsal workflow end to end — baseline, hide, observe across a full business cycle, then drop — and why rebuild cost makes the reversibility valuable.
Own the index-lifecycle policy: how indexes get proposed, reviewed and retired on hot collections, and how you keep the count low without risking a plan regression nobody notices until quarter end.
## The problem it solves You have a collection with a dozen indexes accumulated over three years, and you believe two of them are dead weight. Dropping an index takes a moment. Discovering a week later that one of them was the only thing keeping a quarterly report from taking twenty minutes is not so quick to fix: rebuilding a large index on a live cluster is an hours-long operation that consumes CPU, I/O and cache on every member. Hiding closes that asymmetry. `hidden: true` tells the query planner to pretend the index does not exist. Every query plans and runs exactly as it would after a drop, but the index is still physically there. ```javascript db.orders.hideIndex("status_1_createdAt_-1") // ... observe for a day or two ... db.orders.unhideIndex("status_1_createdAt_-1") // instant ``` You can also set it at creation time — `createIndex(keys, { hidden: true })` — to stage an index without exposing it to the planner yet, then reveal it during a controlled window. ## What stays true while an index is hidden This is where interviewers probe, because the answer is not "it is disabled": - **It is still maintained.** Every insert, update and delete still writes to it. Hiding therefore buys you **no** write-throughput or storage relief, and observing no change in write latency after hiding tells you nothing about what a drop would give you. - **Constraints still apply.** A hidden unique index still rejects duplicate keys with a duplicate key error. Hiding is not a way to relax a constraint temporarily. - **TTL still expires.** A hidden TTL index keeps deleting expired documents on the usual schedule. - **It is still listed.** `getIndexes()` and `listIndexes` show it, with the `hidden` flag set, so it does not vanish from your tooling or your index inventory. - **`hint()` on it fails.** You cannot force a hidden index; asking for it is an error. That is deliberate — if hinting worked, hiding would not faithfully simulate absence. ## What changes Only plan selection. The planner will not choose it, so queries that depended on it fall back to whatever the next-best access path is — often a `COLLSCAN` or a less selective index. Toggling visibility also drops the plan cache for that collection, so plans are re-evaluated immediately rather than reusing cached winners. ## Running the experiment properly Hiding gives you a clean signal only if you look at the right things. Before hiding, capture the baseline: `$indexStats` for usage counters, the current p99 for the operations you care about, and the plans of the queries you suspect. Then hide, and watch for at least a full business cycle — an index used only by a nightly job or a monthly report shows zero usage for 29 days. `$indexStats` counters alone are a weaker signal than the hidden-index rehearsal, because they tell you the index *was* used but not how badly its absence would hurt. Watch for slow-query log entries appearing where there were none, a jump in `COLLSCAN` plans, and latency regressions on read paths. If nothing moves, drop the index for real — the maintenance cost is only reclaimed by an actual drop. ## Where it fits in index lifecycle A disciplined index lifecycle on a busy production collection looks like: propose the index from a real slow query; build it (on a large collection, with the rolling procedure or during a low-traffic window); measure with `explain` that the intended queries use it; periodically review `$indexStats` for candidates that are never chosen; hide the candidates; observe; drop. Hiding is the step that makes the last transition reversible, and it is the reason the feature exists. The adjacent judgement call is how many indexes a hot collection should carry at all. Every extra index means another structure written on each insert and on every update that touches its keys, more of the WiredTiger cache spent on index pages rather than documents, and a longer index build during any resync. That pressure is what makes pruning worth doing, and hidden indexes are how you prune without gambling.
- Does hiding an index reduce write amplification on the collection?No. The index is still updated by every write that touches its keys, so insert and update cost is unchanged, and it still occupies cache and disk. Only an actual drop reclaims that. Hiding is purely a planner-visibility change whose value is that it makes the read-side consequences of a drop observable and instantly reversible.
- Why is $indexStats alone not enough to decide an index is safe to drop?It shows how often the index was chosen, but not what would happen without it. A counter of zero may simply mean the window you looked at missed a monthly report, and a low non-zero counter tells you nothing about how badly those few queries would degrade. Hiding, then watching plans and latency across a full business cycle, is the stronger signal.
- Can you build an index as hidden from the start, and why would you?Yes, createIndex accepts hidden: true. It lets you pay the build cost during a quiet window without letting the planner start using it, then reveal it at a moment you control and can watch. It is useful when you want plan changes to land as a discrete, observable event rather than mid-build.
It is unplugging an appliance to see whether anyone complains, rather than throwing it out and finding out you cannot buy another one until next week.
saying these in an interview costs you the question
- Claims hiding stops the index being maintained on writes
- Says a hidden unique index no longer rejects duplicates
- Thinks hiding disables TTL expiry
- Believes hint() can still force a hidden index
- Treats hiding as a way to reduce storage or write cost