Cosmos DB documents don’t actually expire; they just get marked for deletion by a background process.
Let’s watch a document disappear.
First, we’ll create a container in Cosmos DB with a TTL policy. This policy tells Cosmos DB how long to keep documents before marking them for deletion.
{
"id": "mycontainer",
"partitionKey": {
"paths": [
"/categoryId"
],
"kind": "Hash"
},
"defaultTtl": 60
}
Here, defaultTtl is set to 60 seconds. Any document added to this container will be automatically deleted after 60 seconds from the moment it was created or last modified.
Now, let’s insert a document. We’ll add a created timestamp to track when it was inserted.
{
"id": "mydocument1",
"categoryId": "electronics",
"name": "Smartwatch",
"price": 199.99,
"created": "2023-10-27T10:00:00Z"
}
If we query for mydocument1 immediately after insertion, we’ll find it.
SELECT * FROM c WHERE c.id = 'mydocument1'
After 60 seconds, if we run the same query, the document will no longer be returned. It’s not gone instantly; it’s just no longer visible through normal queries. Cosmos DB’s internal garbage collection process will eventually reclaim the storage space.
The key to TTL is a timestamp property on your documents. You can either use the system-generated _ts property (which is a Unix timestamp representing the last modification time) or a custom property like created or expiryDate.
If you use a custom property, you need to configure the TTL policy to point to it. For example, if your documents have an expiryDate property:
{
"id": "mycontainer",
"partitionKey": {
"paths": [
"/categoryId"
],
"kind": "Hash"
},
"ttl": "expiryDate"
}
This tells Cosmos DB to use the value in the expiryDate field as the expiration time for each document. The expiryDate must be a Unix epoch timestamp in seconds.
You can also set TTL at the individual document level, overriding the container’s default.
{
"id": "mydocument2",
"categoryId": "books",
"title": "The Hitchhiker's Guide to the Galaxy",
"created": "2023-10-27T10:05:00Z",
"ttl": 30
}
This document will expire in 30 seconds, regardless of the container’s defaultTtl of 60 seconds.
The TTL feature is managed by a background garbage collection service within Cosmos DB. This service periodically scans for documents whose TTL has expired and marks them for deletion. The actual physical deletion and space reclamation happen asynchronously. This means that even after a document is "expired," it might still consume storage for a short period. The _ts property is automatically updated by the system and can be used with the defaultTtl setting without any document modification.
If you set a defaultTtl value of -1 on the container, it disables TTL for all new documents in that container. Existing documents with individual TTL settings will still expire as configured.
The most surprising thing about TTL is that it doesn’t actually delete documents; it just makes them invisible. The storage reclamation is a separate, asynchronous process.
The next concept you’ll encounter is how to manage TTL for documents that are updated, and how the _ts property behaves in those scenarios.