The Key-Value Store API lets you store and retrieve data as key-value pairs in the cloud. Each app gets its own store in each user's account.
You can set, get, and delete keys, list them by prefix, increment and decrement numbers, change parts of a stored object, and set keys to expire. Apps use it to persist app data, cache results, and store settings.
Puter.js runs the infrastructure, so there are no servers to set up, scale, or back up. With the User-Pays Model, each user covers their own storage, read, and write costs.
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
puter.kv.set('name', 'Puter Smith').then((success) => {
puter.print(`Key-value pair created/updated: ${success}`);
});
</script>
</body>
</html>
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
(async () => {
// (1) Create a new key-value pair
await puter.kv.set('name', 'Puter Smith');
puter.print("Key-value pair 'name' created/updated<br>");
// (2) Retrieve the value of key 'name'
const name = await puter.kv.get('name');
puter.print(`Name is: ${name}`);
})();
</script>
</body>
</html>
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
puter.kv.incr('testIncrKey').then((newValue) => {
puter.print(`New value: ${newValue}`);
});
</script>
</body>
</html>
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
puter.kv.decr('testDecrKey').then((newValue) => {
puter.print(`New value: ${newValue}`);
});
</script>
</body>
</html>
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
(async () => {
// create a new key-value pair
await puter.kv.set('name', 'Puter Smith');
puter.print("Key-value pair 'name' created/updated<br>");
// delete the key 'name'
await puter.kv.del('name');
puter.print("Key-value pair 'name' deleted<br>");
// try to retrieve the value of key 'name'
const name = await puter.kv.get('name');
puter.print(`Name is now: ${name}`);
})();
</script>
</body>
</html>
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
(async () => {
// (1) Create a number of key-value pairs
await puter.kv.set('name', 'Puter Smith');
await puter.kv.set('age', 21);
await puter.kv.set('isCool', true);
puter.print("Key-value pairs created/updated<br><br>");
// (2) Retrieve all keys
const keys = await puter.kv.list();
puter.print(`Keys are: ${keys}<br><br>`);
// (3) Retrieve all keys and values
const key_vals = await puter.kv.list(true);
puter.print(`Keys and values are: ${(key_vals).map((key_val) => key_val.key + ' => ' + key_val.value)}<br><br>`);
// (4) Match keys with a pattern
const keys_matching_pattern = await puter.kv.list('is*');
puter.print(`Keys matching pattern are: ${keys_matching_pattern}<br>`);
// (5) Delete all keys (cleanup)
await puter.kv.del('name');
await puter.kv.del('age');
await puter.kv.del('isCool');
})();
</script>
</body>
</html>
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
(async () => {
// (1) Create a number of key-value pairs
await puter.kv.set('name', 'Puter Smith');
await puter.kv.set('age', 21);
await puter.kv.set('isCool', true);
puter.print("Key-value pairs created/updated<br>");
// (2) Retrieve all keys
const keys = await puter.kv.list();
puter.print(`Keys are: ${keys}<br>`);
// (3) Flush the key-value store
await puter.kv.flush();
puter.print('Key-value store flushed<br>');
// (4) Retrieve all keys again, should be empty
const keys2 = await puter.kv.list();
puter.print(`Keys are now: ${keys2}<br>`);
})();
</script>
</body>
</html>
These Key-Value Store features are supported out of the box when using Puter.js:
puter.kv.set() - Set a key-value pairputer.kv.get() - Get a value by keyputer.kv.del() - Delete a key-value pairputer.kv.list() - List keys in ascending or descending orderputer.kv.incr() - Increment a numeric valueputer.kv.decr() - Decrement a numeric valueputer.kv.update() - Update values by pathputer.kv.add() - Add values to an existing keyputer.kv.remove() - Remove values by pathputer.kv.expire() - Set key expiration in secondsputer.kv.expireAt() - Set key expiration timestampputer.kv.flush() - Clear all dataputer.kv.share() - Share the keys under a prefix with another userputer.kv.unshare() - Stop a share, as its owner or its holderputer.kv.listShared() - List the shares other users made with youputer.kv.listSharedByMe() - List the shares you madeputer.kv.MAX_KEY_SIZE - Maximum key size in bytesputer.kv.MAX_VALUE_SIZE - Maximum value size in bytesA user can share the keys under a prefix with another Puter user. The user who shares is the share's owner, and the user it's shared with is its holder. The keys stay in the owner's store.
Pick the tool by what you want to do:
| You want to… | Use |
|---|---|
| Let another user see or change part of your app's data | puter.kv.share() |
| Let another app of the same user use your data | puter.perms.request('appData', …) |
| Share files | puter.fs.share() |
| Show data to anyone, signed in or not | Hosting or a worker. A share is for one user, who needs a Puter account. |
| Enforce rules per writer, such as letting each user edit only their own posts | A prefix per writer, each shared separately, or a worker that checks each write |
A share has one of three levels, and each includes the ones before it:
watch: the holder gets events when keys under the prefix change, and can list the keys without their values.read: the holder can also read values.write: the holder can also change and delete any key under the prefix.An app shares its user's data only with that user's consent, which it asks for once with puter.perms.request('kvShare', …).
The holder finds the share with puter.kv.listShared() and passes its handle to the other puter.kv methods, in the same app or outside any app. Keys are relative to the shared prefix. Here the owner writes list:<id>:meta, and the holder reads the same key as meta:
// The owner, once per app: let this app share `list:` keys with write access
await puter.perms.request('kvShare', { prefix: 'list:', access: 'write' });
const prefix = `list:${crypto.randomUUID()}:`;
await puter.kv.set(`${prefix}meta`, { title: 'Groceries' });
await puter.kv.share(prefix, 'alice', 'write');
// Alice, in the same app
const { items } = await puter.kv.listShared();
const { handle } = items[0];
const meta = await puter.kv.get('meta', { handle });
await puter.kv.set(`item:${crypto.randomUUID()}`, { text: 'milk' }, { handle });
const entries = await puter.kv.list('item:*', true, { handle });
notify: true lets the owner and the holder send each other notifications through its handle with puter.notifications.notify(), and tells the holder about the share inside your app. See What the holder sees.disableSharing can't be read or listed through a share. Keep them outside the prefixes you share.chg:<timestamp>-<random>, instead of updating one shared counter.Either side ends a share with puter.kv.unshare(). See Rate Limits and Quotas for how many shares an account can make and hold.
These recipes show sharing in a full app:
You can see various Puter.js Key-Value Store features in action from the following examples: