If you’ve worked with MongoDB long enough, you’ve probably used TTL indexes at least once.
And if you’ve worked in production long enough, you’ve probably seen them surprise someone.
TTL (Time-To-Live) indexes are one of those features that look simple:
“Create an index, set expireAfterSeconds, and MongoDB deletes old documents automatically.”
And yes — that’s true.
But what many teams don’t realize is that TTL quietly becomes part of your data lifecycle design. And once that happens, small misunderstandings can turn into very real production impact.
Let’s walk through this properly.
What a TTL Index Really Does
A TTL index tells MongoDB to automatically remove documents after a specified time.
It must be created as a single-field index on a field of type:
- Date
- or an array of Dates
Example:

After roughly one hour, the document becomes eligible for deletion.And that word matters — eligible.MongoDB’s TTL monitor runs approximately once per minute. Expiration timing is not exact. Under load, deletions can be delayed. So if your logic depends on something disappearing exactly at the 3600th second — TTL is not the right tool.
Also important:
If the indexed field is an array of Dates, MongoDB uses the earliest date in the array to determine expiration.And if the field is not a BSON Date (for example, a string formatted like a date), TTL will simply ignore it.
Why TTL Feels So Convenient
Without TTL, teams often build:
- Cleanup scripts
- Cron jobs
- Background workers
- Expiration services
Each of those needs monitoring. Each can fail silently.TTL moves expiration logic inside the database engine. No extra job to deploy. No extra infrastructure.Less moving parts.And that’s exactly why TTL is powerful.But power without clarity becomes risk.
Where Things Start Getting Risky
TTL is not dangerous by design.It becomes dangerous when assumptions are unclear.
Let’s talk about the common production misunderstandings.
1. “Expiration Is Real-Time”
It isn’t.
The TTL monitor runs roughly every minute from mongod startup. Expired documents are removed in batches. Under heavy write load, deletions may lag.
TTL is not suitable for:
- Security enforcement
- Precise billing cutoffs
- SLA-bound expiration logic
If timing matters, your application must still enforce it.
Instead of a fixed lifetime, documents can carry their own expiration timestamp:
example:

2. “TTL Deletes Are Invisible”
By default, yes.
There is:
- No trigger system
- No built-in audit log
From the application’s point of view, the document simply disappears.
However — and this is important for enterprise systems — TTL deletions can be observed using Change Streams:
db.collection.watch([ { $match: { operationType: "delete" } }])
TTL-triggered deletes generate normal delete events in the oplog, and change streams can capture them.
So TTL isn’t untraceable — but you must intentionally monitor it.
If you need compliance-grade traceability, combine TTL with:
- Soft delete fields
- Change streams
- Or external auditing pipelines
3. “Only One TTL Index per Collection”
This is a common misconception.
MongoDB allows multiple TTL indexes per collection, provided:
- Each is a single-field index
- They are on different fields
- They are not compound indexes
- They are not hashed
For example:
You might have:
- createdAt → expireAfterSeconds: 3600
- expiresAt → expireAfterSeconds: 0 (absolute expiration)
Each operates independently.
Design constraints exist — but they are not as restrictive as often assumed.
4. Updating Expiration Settings
You can modify expireAfterSeconds on an existing TTL index using:
db.runCommand({ collMod: "sessions", index: { keyPattern: { createdAt: 1 }, expireAfterSeconds: 7200 }})
If you are converting a normal single-field index into a TTL index, you may need to drop and recreate it.
After any change, always verify:
db.sessions.getIndexes()
Never assume the change applied correctly in production.
What Production Actually Looks Like
TTL doesn’t usually break loudly.
It causes:
- Background deletes
- Index updates
- Oplog growth
- Replication activity
- Storage churn
And this is where real incidents happen.
Delete Storms
If you enable TTL on a collection that already contains millions of expired documents, MongoDB will begin deleting them in batches.
That means:
- Delete ops/sec spike
- CPU rises
- Disk IOPS increase
- Oplog grows rapidly
- Replication lag may appear
Always count expired documents before enabling TTL:
db.sessions.countDocuments({ createdAt: { $lt: new Date(Date.now() - 3600 * 1000) }})
If the number is large, pre-delete in controlled batches.
Replication Lag
TTL deletions execute on the primary and replicate via the oplog like any other delete.
In replica sets:
- Oplog window can shrink
- Secondaries can fall behind
- Monitoring alerts can trigger
In sharded clusters:
- Deletions occur on the shard that owns the expired documents
- Oplog churn can still become significant
Check replication health before enabling TTL on large datasets.
Storage Reality
TTL reduces document count.
It does not instantly shrink disk size.
With WiredTiger (the default storage engine):
- Deleted space is marked reusable internally
- Disk fragmentation may remain
- OS-level file size may not shrink immediately
Space may be reused naturally over time.
For significant reclamation, you may need:
- compact
- Or replica resync
Monitor both:
- Document count
- db.collection.stats()
- wiredTiger.cache metrics
- Disk IOPS
Otherwise, teams sometimes assume “TTL isn’t working” — when it actually is.
When TTL Works Best
TTL is excellent for:
- User sessions
- Password reset tokens
- OTP records
- Temporary job states
- Rate-limiting counters
- Short-lived analytics events
TTL is risky for:
- Financial records
- Audit logs
- Compliance data
- User-generated content
If deleting the data would trigger a legal discussion — TTL is not your first tool.
Production Rollout Checklist
Before enabling TTL:
- Expiration field is BSON Date (or array of Dates)
- Field exists on documents intended to expire
- Expired document count is measured
- Oplog capacity reviewed
- Backup taken
- Replication healthy
After enabling:
Monitor:
- serverStatus().metrics.ttl.deletedDocuments
- Delete operations/sec
- CPU and disk IOPS
- Replication lag
- Oplog growth
Watch for periodic spikes — TTL activity often shows patterns.
Final Thoughts
TTL indexes are not a minor feature.They quietly define how long your data is allowed to exist.In small systems, they feel convenient.In production systems, they become architectural.Used intentionally, TTL simplifies operations and reduces moving parts.
Used casually, it can:
- Trigger delete storms
- Stress replication
- Create silent compliance gaps
- Surprise teams months later
Like many MongoDB features, the tool itself is not the problem.The difference is whether you treat TTL as a shortcut —or as part of your data lifecycle contract.If you’re designing with that mindset, TTL becomes one of the most elegant features in MongoDB.If you’re not, it becomes one of the most misunderstood.