Not every index has to cover every document, and the ones that do not are quietly some of the most efficient indexes you can build. Sparse and partial indexes leave documents out on purpose, which makes them smaller, cheaper to write, and lighter in memory. They solve the same family of problem from two angles. Partial is the more powerful of the two, and usually the one to reach for.
Sparse: index only where the field exists
A sparse index includes a document only if it has the indexed field. Missing the field means missing from the index:
db.users.createIndex({ phone: 1 }, { sparse: true })
If only a fraction of your users have a phone number, a plain index still stores an entry for every user, most of them null. A sparse index stores entries only for the users who actually have a phone, so it is smaller and cheaper. The field is optional, so the index is too.
The catch: a sparse index is incomplete by design, so MongoDB will not use it for a query or sort that needs every document, because the answer would be missing the ones the index skipped. That limitation is exactly what the partial index fixes.
Partial: index only what matches a filter
A partial index includes documents matching any filter you write, not just "the field exists." This is more expressive and, in most cases, the better tool:
db.orders.createIndex(
{ shippedAt: 1 },
{ partialFilterExpression: { status: "active" } }
)
If your queries only ever look at active orders, why index the archived ones? This index covers only the active subset, so it is a fraction of the size and cost of a full index, and it does exactly as much work as your queries need.
There is one rule that trips people up. MongoDB only uses a partial index when the query is guaranteed to hit a subset of the index's filter. So a query for active orders can use the index above; a query with no status condition cannot, because it might need the archived orders the index excludes. Your query has to include the filter, or a stricter version of it. The partial index docs spell out the matching rules.
Which one to use
For new indexes, reach for partial. It does everything sparse does (partialFilterExpression: { field: { $exists: true } } is a sparse index in partial clothing) and a great deal more, and MongoDB itself points you toward it. Sparse still shows up in older schemas and in the specific "only where this field exists" case, so it is worth recognizing, but partial is the one to build.
Partial also fixes the awkward corner of unique indexes: a partial unique index enforces uniqueness only among the documents that have the field, so an optional-but-unique field (an email that not every user sets) works the way you would expect.
Smaller indexes, same coverage
The whole point of both is a leaner index that still serves your real queries, which is the heart of index optimization: the smallest set of indexes, each as small as it can be, that covers what you actually run. A partial index on a hot subset can be a fraction of the size of the full index it replaces, paid back on every write.
mongoui's Index view shows each index with its storage and how often it is used, so you can see whether a full index would be better off partial, or whether a partial one is even being hit given its filter rule. That inventory runs on your machine and makes no AI call. Full documents and MongoDB credentials stay local. Index the subset your queries touch, keep the filter in the query, and let the rest of the collection go un-indexed.
