Creating and Managing a MongoDB TTL Index to Auto‑Expire Documents
Learn how to create, test, and maintain a MongoDB TTL index that automatically removes expired documents, with step‑by‑step commands, verification, and rollback instructions.
23 Dec 2025, 22:20 UTC

Desired Outcome
Create a TTL (time-to-live) index on a MongoDB collection so that documents are automatically removed after a defined period, without manual cleanup scripts.
Prerequisites
- MongoDB server version 2.2 or newer (the examples assume 4.4+ for replica-set safety).
- A database and collection where you want automatic expiration.
- The field that will hold the expiration timestamp must be of BSON
Datetype (or an array of dates). - User credentials with
readWriteon the database anddbAdmin(ordbAdminAnyDatabase) to create indexes. - Access to the MongoDB shell (
mongosh) or a compatible driver.
Procedure
1. Identify the expiration field
Choose a field that will always contain a valid date, e.g., expiresAt. If the field can be missing, consider using a default value in your application or a validation rule.
2. Create the TTL index
Run the following command in the mongo shell, replacing mydb, mycoll, and expiresAt with your actual names and setting the desired lifetime in seconds (expireAfterSeconds).
use mydb
db.mycoll.createIndex(
{ expiresAt: 1 },
{ expireAfterSeconds: 86400 } // 24 hours
)
The index is built in the background by default; it does not block reads or writes.
3. Insert a test document to verify behavior
Insert a document whose expiration date is set a few seconds in the past. This forces the TTL mechanism to consider it expired immediately (subject to the 60‑second background sweep).
const testId = new ObjectId()
db.mycoll.insertOne({
_id: testId,
expiresAt: new Date(Date.now() - 10000), // 10 seconds ago
data: 'sample'
})
4. Wait and check removal
After waiting longer than the sum of expireAfterSeconds (if you used a future date) or at least 70 seconds for the past‑date test, run:
db.mycoll.countDocuments({ _id: testId })
The command should return 0 if the document was deleted.
5. Confirm the TTL action in the server log
Look for lines similar to:
[ttl] deleted 1 documents from collection mydb.mycoll because of ttl index
On a replica set, repeat the count check on a secondary by setting read preference:
db.getSiblingDB('mydb').getCollection('mycoll', { readPreference: { mode: 'secondary' } })
.countDocuments({ _id: testId })
Expected Checks
- Index definition:
db.mycoll.getIndexes()should show an index with pattern{ expiresAt: 1 }and an options field containingexpireAfterSeconds. - Test document removal: count returns
0after the expected wait. - Log evidence:
mongodlog contains a TTL deletion message for the test. - No impact on unique constraints: attempting to create a unique index on the same field will fail, confirming the TTL restriction.
Recovery Options (Rollback)
Creating a TTL index modifies the collection’s index list. To revert:
db.mycoll.dropIndex({ expiresAt: 1 })Dropping the index stops future automatic deletions but does not affect documents that have already been removed. If you need to retain the existing documents, ensure you drop the index before the background thread deletes them.
Limitations and Practical Tips
- The TTL index cannot be compound; only a single field may be indexed.
- It cannot coexist with a unique index on the same field.
- Capped collections ignore TTL indexes.
- Missing or malformed
Datevalues cause either immediate deletion (if the value isnullor0) or no expiration at all. Validate the field in your application schema. - Deletion latency: expect up to 60 seconds for the background thread plus the
expireAfterSecondsperiod. For sub‑minute expiry requirements, consider application‑level cleanup. - High delete rates can increase the oplog size on replica sets; monitor
oplog.rssize andreplSetGetStatuslag.
Verification Checklist
- Run
db.mycoll.getIndexes()and verify the TTL options. - Insert a test document with a known past date.
- Wait at least 70 seconds.
- Run
db.mycoll.countDocuments({ _id: testId }); expect0. - Check
mongodlog for a TTL deletion line. - (Optional) Repeat on a secondary with readPreference secondary.
When the checklist passes, the TTL index is correctly configured and the automatic expiration mechanism is operating as intended.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.