---
title: "How do you clean up stale or expired data periodically in IndexedDB (e.g., TTL)?"  
description: "How do you clean up stale or expired data periodically in IndexedDB (e.g., TTL)?"  
author: "ICSM Computer"  
published: 2025-07-18  
updated: 2025-07-18  
canonical: https://www.mindstick.com/interview/34338/how-do-you-clean-up-stale-or-expired-data-periodically-in-indexeddb-e-g-ttl  
category: "IndexedDB"  
tags: ["database", "indexeddb"]  
reading_time: 4 minutes  

---

# How do you clean up stale or expired data periodically in IndexedDB (e.g., TTL)?

> To clean up **stale or expired data (TTL: Time-To-Live)** periodically in **IndexedDB**, you need to **manually implement** a cleanup strategy since IndexedDB has **no built-in TTL or expiration** mechanism.

Here’s a complete approach:

## Strategy to Clean Stale/Expired Data in [IndexedDB](https://www.mindstick.com/interview/34289/what-is-indexeddb)

### 1. Store Timestamps with Your Data

Include an `updatedAt` or `expiresAt` field (timestamp) in each record:

```javascript
{
  id: 'abc123',
  name: 'Item',
  data: '...',
  updatedAt: Date.now(),         // OR
  expiresAt: Date.now() + 3600 * 1000 // 1 hour TTL
}
```

### 2. Periodic Cleanup Function

You can create a scheduled cleanup function that deletes expired records.

```javascript
async function cleanupExpiredData(db, tableName, ttlMs) {
  const now = Date.now();
  const table = db.table(tableName);

  await table.where('updatedAt').below(now - ttlMs).delete();
}
```

Or if using `expiresAt`:

```javascript
await table.where('expiresAt').below(Date.now()).delete();
```

### 3. Schedule Cleanup Periodically

There are a few ways to trigger cleanup:

#### On App Start:

```javascript
await cleanupExpiredData(db, 'cache', 3600 * 1000); // Clean data older than 1 hour
```

#### With `setInterval`:

```javascript
setInterval(() => {
  cleanupExpiredData(db, 'cache', 3600 * 1000);
}, 5 * 60 * 1000); // Every 5 minutes
```

#### On Tab Visibility Change:

```javascript
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "visible") {
    cleanupExpiredData(db, 'cache', 3600 * 1000);
  }
});
```

### 4. Optional: Use an Index for `expiresAt` (Performance Boost)

When defining your IndexedDB schema (e.g., with Dexie.js):

```javascript
db.version(1).stores({
  cache: 'id, expiresAt'
});
```

Then you can query efficiently with:

```javascript
await db.cache.where('expiresAt').below(Date.now()).delete();
```

### 5. Add Guard on Read (to prevent use of expired records)

```javascript
const item = await db.cache.get('abc123');

if (item && item.expiresAt < Date.now()) {
  await db.cache.delete(item.id);
  return null; // expired
}

return item;
```

## Example with Dexie.js

```javascript
const db = new Dexie("MyApp");
db.version(1).stores({
  cache: 'id, expiresAt'
});

async function storeItem(id, data, ttl = 3600 * 1000) {
  await db.cache.put({
    id,
    data,
    expiresAt: Date.now() + ttl
  });
}

async function cleanupTTL() {
  await db.cache.where('expiresAt').below(Date.now()).delete();
}

setInterval(cleanupTTL, 5 * 60 * 1000); // Clean every 5 mins
```

## Summary

| Step | Action |
| --- | --- |
| Add timestamp fields | `updatedAt` or `expiresAt` |
| Write cleanup logic | Use `where(...).below(...).delete()` |
| Schedule cleanup | `setInterval`, `visibilitychange`, or on startup |
| Guard access | Don’t return expired records |
| Use index | For efficient expiration queries |

## Answers

### Answer by ICSM Computer

> To clean up **stale or expired data (TTL: Time-To-Live)** periodically in **IndexedDB**, you need to **manually implement** a cleanup strategy since IndexedDB has **no built-in TTL or expiration** mechanism.

Here’s a complete approach:

## Strategy to Clean Stale/Expired Data in [IndexedDB](https://www.mindstick.com/interview/34289/what-is-indexeddb)

### 1. Store Timestamps with Your Data

Include an `updatedAt` or `expiresAt` field (timestamp) in each record:

```javascript
{
  id: 'abc123',
  name: 'Item',
  data: '...',
  updatedAt: Date.now(),         // OR
  expiresAt: Date.now() + 3600 * 1000 // 1 hour TTL
}
```

### 2. Periodic Cleanup Function

You can create a scheduled cleanup function that deletes expired records.

```javascript
async function cleanupExpiredData(db, tableName, ttlMs) {
  const now = Date.now();
  const table = db.table(tableName);

  await table.where('updatedAt').below(now - ttlMs).delete();
}
```

Or if using `expiresAt`:

```javascript
await table.where('expiresAt').below(Date.now()).delete();
```

### 3. Schedule Cleanup Periodically

There are a few ways to trigger cleanup:

#### On App Start:

```javascript
await cleanupExpiredData(db, 'cache', 3600 * 1000); // Clean data older than 1 hour
```

#### With `setInterval`:

```javascript
setInterval(() => {
  cleanupExpiredData(db, 'cache', 3600 * 1000);
}, 5 * 60 * 1000); // Every 5 minutes
```

#### On Tab Visibility Change:

```javascript
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "visible") {
    cleanupExpiredData(db, 'cache', 3600 * 1000);
  }
});
```

### 4. Optional: Use an Index for `expiresAt` (Performance Boost)

When defining your IndexedDB schema (e.g., with Dexie.js):

```javascript
db.version(1).stores({
  cache: 'id, expiresAt'
});
```

Then you can query efficiently with:

```javascript
await db.cache.where('expiresAt').below(Date.now()).delete();
```

### 5. Add Guard on Read (to prevent use of expired records)

```javascript
const item = await db.cache.get('abc123');

if (item && item.expiresAt < Date.now()) {
  await db.cache.delete(item.id);
  return null; // expired
}

return item;
```

## Example with Dexie.js

```javascript
const db = new Dexie("MyApp");
db.version(1).stores({
  cache: 'id, expiresAt'
});

async function storeItem(id, data, ttl = 3600 * 1000) {
  await db.cache.put({
    id,
    data,
    expiresAt: Date.now() + ttl
  });
}

async function cleanupTTL() {
  await db.cache.where('expiresAt').below(Date.now()).delete();
}

setInterval(cleanupTTL, 5 * 60 * 1000); // Clean every 5 mins
```

## Summary

| Step | Action |
| --- | --- |
| Add timestamp fields | `updatedAt` or `expiresAt` |
| Write cleanup logic | Use `where(...).below(...).delete()` |
| Schedule cleanup | `setInterval`, `visibilitychange`, or on startup |
| Guard access | Don’t return expired records |
| Use index | For efficient expiration queries |


---

Original Source: https://www.mindstick.com/interview/34338/how-do-you-clean-up-stale-or-expired-data-periodically-in-indexeddb-e-g-ttl

Copyright © MindStick Software Pvt. Ltd. This Markdown version is provided for developers, AI systems, and offline reading.
