Store Temporary Data


In some cases, you might want to store data only for a while. With puter.kv, you can set a TTL (time to live) or an expiry time on a key. When the time is up, the key is removed automatically.

Expire a Value

To have a key delete itself after a while, write it, then call the puter.kv.expire() method with the number of seconds it should live:

await puter.kv.set('promoDismissed', true);
await puter.kv.expire('promoDismissed', 60 * 60 * 24);   // 24 hours

The seconds are counted on the server, so a wrong clock on the user's device doesn't change when the key expires.

Write the value first. On a key that doesn't exist yet, puter.kv.expire() creates an empty marker instead, as in Set a Lock or Cooldown.

Check Whether It Expired

Once the time passes, puter.kv.get() returns null, the same as for a key that was never written:

const dismissed = await puter.kv.get('promoDismissed');

if ( ! dismissed ) {
    showPromo();
}

The key is gone the moment the TTL runs out. From then on, puter.kv.list() leaves it out too, so you never have to filter out stale entries yourself.

Expire at a Set Time

To expire a key at a specific moment instead, such as the end of a sale or midnight, use the puter.kv.expireAt() method with a Unix timestamp in seconds:

const midnight = new Date();
midnight.setHours(24, 0, 0, 0);

await puter.kv.expireAt('promoDismissed', Math.floor(midnight.getTime() / 1000));

JavaScript dates count in milliseconds, so divide by 1000. A millisecond value reads as a date tens of thousands of years away, and the key never expires.

The timestamp comes from the user's device, so midnight here is midnight in the user's time zone. For a plain duration, use puter.kv.expire().

A timestamp that has already passed, including 0, expires the key right away.

Set a Lock or Cooldown

Calling puter.kv.expire() on a key that doesn't exist creates an empty marker that removes itself when the TTL runs out. You can use the marker as a basic lock or cooldown, such as waiting 10 minutes before sending another reminder, or running one sync at a time.

The puter.kv.get() method reads a marker as null, the same as a missing key. To check whether the marker exists, use puter.kv.list() instead:

async function isLocked (key) {
    const { items } = await puter.kv.list({ pattern: key, limit: 1 });
    return items[0] === key;
}

if ( ! await isLocked('lock:sync') ) {
    await puter.kv.expire('lock:sync', 30);   // held for 30 seconds
    await sync();
}

The list is sorted, and a key comes first among the keys that start with it, so the first item is the marker when it exists. An expired marker is left out of the list.

When the tab closes in the middle of a sync, the marker still removes itself when the TTL runs out. To release the lock early, delete the key with the puter.kv.del() method. Two tabs that check at the same moment can both see the lock as free, so use it where running twice is harmless.

Cache a Response

To cache something you fetch, pass the expiry as the third argument of puter.kv.set(). It takes the same timestamp in seconds as puter.kv.expireAt(), and sets the value and the TTL in one write:

async function getForecast (city) {
    const key = `forecast:${ city }`;

    const cached = await puter.kv.get(key);
    if ( cached ) return cached;

    const forecast = await fetchForecast(city);
    const inOneHour = Math.floor(Date.now() / 1000) + 60 * 60;
    await puter.kv.set(key, forecast, inOneHour);
    return forecast;
}

Every call to puter.kv.set() replaces the whole entry, TTL included. A value you write again and again, such as a draft saved on every edit, needs the expiry on every write. Each save then moves the expiry later:

const inOneWeek = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7;

await puter.kv.set('draft', text, inOneWeek);

Remove a TTL

To keep a key for good, write the value again with puter.kv.set() and no expiry. The key then stays until you delete it:

await puter.kv.set('draft', text);

To change part of the value and remove the TTL in the same write, pass null as the TTL of puter.kv.update().

Calls that change part of a value keep the TTL the key already has. That includes puter.kv.incr(), puter.kv.decr(), puter.kv.add(), puter.kv.remove(), and puter.kv.update() without a TTL argument.

Notes

← All recipes