Using DynamoDB Time to Live (TTL) to Automatically Expire Items
Enable TTL on a DynamoDB table, store expiration as a Unix‑epoch‑seconds Number, and understand the asynchronous deletion behavior and common pitfalls.
21 May 2026, 01:43 UTC

Quick answer: enable TTL and store expiration as a Number of seconds
To let DynamoDB automatically remove old items, enable the Time to Live feature on the table and make sure each item contains a Number attribute (commonly named expiresAt) holding a Unix epoch timestamp in seconds. When that timestamp is in the past, DynamoDB marks the item for background deletion at no write‑capacity cost.
How TTL works – mechanism explained
TTL is a table‑level setting. After you enable it, DynamoDB scans items periodically (typically within 48 hours) and compares the value of the designated attribute to the current epoch time. If the stored value is less than the current time, the item is queued for deletion. The deletion is performed by a background process that does not consume the table’s provisioned write capacity units (WCU) or on‑demand write request units, so it does not affect your throughput or cost for writes.
Importantly, the deletion is not synchronous. An item whose expiresAt has passed can still be read by a GetItem or Query until the background cleanup runs. Therefore, applications that require strict correctness must filter out expired items themselves (e.g., with a filter expression expiresAt > :now).
Worked example: enable TTL and write an item
Enable TTL on an existing table (replace
Sessionswith your table name):aws dynamodb update-time-to-live \ --table-name Sessions \ --time-to-live-specification Enabled=true,AttributeName=expiresAtRun this command from a terminal with AWS CLI v2 configured with sufficient IAM permissions (
dynamodb:UpdateTimeToLive).Verify the setting:
aws dynamodb describe-time-to-live --table-name SessionsThe output should show
"TimeToLiveStatus": "ENABLED"and"AttributeName": "expiresAt".Insert an item with a future expiration. In application code (e.g., Node.js) compute the timestamp as seconds:
const nowSec = Math.floor(Date.now() / 1000); const ttlSec = nowSec + 3600; // 1 hour from now const params = { TableName: 'Sessions', Item: { pk: { S: 'user#123' }, sk: { S: 'session#abc' }, expiresAt: { N: ttlSec.toString() }, // must be Number type data: { S: 'session‑payload' } } }; await ddb.putItem(params).promise();Note the
Ntype marker for a Number attribute. If you accidentally store the value as a string (S) or as milliseconds, the item will not be expired.To test immediate expiration, insert an item with a timestamp in the past:
const pastSec = Math.floor(Date.now() / 1000) - 10; // 10 seconds ago // same Item structure, expiresAt: { N: pastSec.toString() }After enabling TTL, the item may still be readable for up to 48 hours; you can confirm it is still present with a
GetItemcall, but you should also see it disappear eventually without any write‑capacity consumption.
Limits and common mistakes
Asynchronous deletion: Do not rely on TTL for immediate removal. Always filter by
expiresAtin reads when stale data would cause incorrect behavior.Attribute type and unit: The TTL attribute must be a
Numberrepresenting epoch seconds. Storing it as a string, using milliseconds, or providing an ISO‑8601 timestamp will prevent expiration.Backfill required for existing items: Enabling TTL does not add the attribute to items already in the table. Those items will never expire unless you update them to include a proper
expiresAtvalue.Impact on streams, backups, and global tables: TTL‑driven deletions appear as ordinary delete events in DynamoDB Streams, are replicated in Global Tables, and are included in on‑demand backups. If downstream systems treat deletes differently, verify their behavior before assuming TTL is a “silent” purge.
No replacement for conditional deletes: TTL cannot enforce business rules such as “delete only if a certain condition holds”. Use conditional writes or transactions when you need that guarantee.
Practical verification steps
- Create a test table (e.g.,
TestTTL) and enable TTL onexpiresAt. - Insert two items: one with
expiresAtset to the current time plus 300 seconds, another set to the current time minus 300 seconds. - Immediately query both items with a filter expression
expiresAt > :now(where:nowis the current epoch seconds). Only the future‑dated item should be returned. - Wait a few minutes, then query again without the filter. The past‑dated item may still appear; after the background cleanup window (typically under 48 hours) it will disappear.
- Run
aws dynamodb describe-time-to-liveto confirm the setting remains enabled.
These steps demonstrate both the automatic deletion behavior and the need for application‑level filtering when correctness matters.
When to use TTL
TTL is well‑suited for high‑churn data where eventual removal is acceptable, such as:
- User sessions or authentication tokens
- Temporary caches (e.g., API rate‑limit counters)
- Log or event buffers that are later archived elsewhere
For data that must be deleted immediately, or where the exact deletion time impacts consistency (e.g., financial transactions), rely on explicit delete operations with appropriate conditions instead of TTL.
Summary
Enable DynamoDB TTL by setting a Number attribute containing epoch seconds. The feature removes items asynchronously without consuming write capacity, but you must filter expired items in reads when stale data would be incorrect, backfill existing items, and verify how streams or downstream consumers interpret the delete events.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.