Creating an index in MongoDB is one line:
db.orders.createIndex({ createdAt: -1 })
That is the whole command. The hard part is not the syntax, it is choosing the right index, in the right order, and not leaving five more behind that do nothing but tax every write. Let us do both: the mechanics first, then the judgment.
The basic syntax
createIndex() takes a key document and an options document. The key names the field and a direction, 1 for ascending or -1 for descending:
db.orders.createIndex({ userId: 1 }) // ascending
db.orders.createIndex({ createdAt: -1 }) // newest first
For a single-field index, the direction barely matters, because MongoDB can read the index forward or backward. It starts to matter the moment you index more than one field.
Compound indexes and the order that matters
A compound index covers more than one field, and the field order is the whole game. The rule is Equality, Sort, Range, in that order:
db.orders.createIndex({ userId: 1, status: 1, createdAt: -1 })
Fields you match exactly (userId, status) come first. The field you sort on (createdAt) comes next. Range filters ($gt, $lt, $in) come last. Follow that order and one index serves a query like this without ever loading documents into memory to sort them:
db.orders
.find({ userId: 123, status: "shipped" })
.sort({ createdAt: -1 })
Get the order wrong and MongoDB either ignores the index or does the sort in memory, which is the thing you were trying to avoid. One well-ordered compound index frequently replaces three single-field ones, which is a strict upgrade: fewer indexes to maintain, less write cost, same coverage. The MongoDB indexes manual has the full treatment.
The options worth knowing
Most of an index's power lives in the second argument:
db.users.createIndex({ email: 1 }, { unique: true })
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
db.profiles.createIndex({ phone: 1 }, { sparse: true })
A unique index refuses to store two documents with the same value, which is the cleanest way to stop duplicates at the source (build it after clearing existing ones, or the build trips over them). A TTL index, set with expireAfterSeconds, quietly deletes documents once a date field ages past the limit, which is how you expire sessions and logs without a cron job. A sparse or partial index only covers the documents that have the field, so it stays small and costs less on writes.
Confirm the index is actually earning its keep
An index you created is not the same as an index MongoDB uses. Check with explain():
db.orders
.find({ userId: 123, status: "shipped" })
.explain("executionStats")
Read winningPlan.stage. An IXSCAN means your index is doing its job. A COLLSCAN means MongoDB is reading every document anyway, which is a sign the field order is off or the query does not match the index. The explain results reference covers the fields. If you are here because a query is slow, that is its own topic: see why your MongoDB query is slow.
When not to create an index
Every index speeds up a read and taxes every write, and it takes storage and memory. So the honest advice is: do not index on a hunch. An index nobody queries is pure overhead, paid forever, and they pile up faster than you would think. Before adding one, confirm a real query needs it. After adding a few, check $indexStats and drop the ones sitting at zero uses. That maintenance loop is MongoDB index optimization, and it is where most databases quietly lose performance: not too few indexes, too many.
mongoui shows the whole index budget at once, which indexes serve queries and which just cost writes, side by side with the storage each one takes. It reads the same $indexStats and explain() output you would run by hand, then reports it in plain English, on your machine, without your data leaving your network. Create the index a query needs, skip the three it does not, and your write path stays as fast as your read path.
