KV Store
The KV Store provides fast, namespaced key-value storage. Access it through platform.env.KV.{namespace} where {namespace} is any name you choose to organize your data.
import { getPlatform } from '@maravilla-labs/platform';
const platform = getPlatform();
// "demo" is the namespace
await platform.env.KV.demo.put('greeting', 'hello world');
const value = await platform.env.KV.demo.get('greeting');
API Reference
get(key)
Retrieves a value by key. Returns the stored value as a string, or null if the key does not exist.
const value = await platform.env.KV.myapp.get('user:abc');
if (value === null) {
console.log('Key not found');
}
put(key, value, options?)
Stores a value under the given key. Overwrites any existing value for that key.
Parameters:
key(string) — the key to store the value undervalue(string) — the value to storeoptions(object, optional):ttl(number) — time-to-live in seconds; the key will be automatically deleted after this duration
// Store a value permanently
await platform.env.KV.sessions.put('session:xyz', JSON.stringify({ userId: '123' }));
// Store a value that expires in 1 hour
await platform.env.KV.sessions.put('session:xyz', JSON.stringify({ userId: '123' }), {
ttl: 3600
});
delete(key)
Deletes a key and its associated value. No error is thrown if the key does not exist.
await platform.env.KV.demo.delete('todo:abc123');
list(options?)
Lists keys in the namespace. Supports prefix filtering and cursor-based pagination for iterating over large datasets.
Parameters (options object):
prefix(string, optional) — only return keys that start with this prefixlimit(number, optional) — maximum number of keys to return (max 1000)cursor(string, optional) — pagination cursor from a previouslistcall
Returns:
{
result: Array<{ name: string; expiration?: number }>;
success: boolean;
result_info: {
cursor?: string; // present if there are more results
count: number; // number of keys returned
};
}
// List all keys with a prefix
const result = await platform.env.KV.demo.list({ prefix: 'todo:', limit: 50 });
for (const key of result.result) {
console.log(key.name); // e.g. "todo:abc123"
console.log(key.expiration); // Unix timestamp (seconds), if set
}
Paginating Through All Keys
Use the returned cursor to fetch subsequent pages:
let cursor = undefined;
const allKeys = [];
do {
const result = await platform.env.KV.myapp.list({
prefix: 'user:',
limit: 100,
cursor
});
allKeys.push(...result.result);
cursor = result.result_info.cursor;
} while (cursor);
console.log(`Found ${allKeys.length} keys`);
Data Serialization
The KV Store stores values as strings. To store objects, arrays, or other complex types, serialize them with JSON.stringify and deserialize with JSON.parse:
// Storing an object
const todo = { id: 'abc', text: 'Buy groceries', done: false };
await platform.env.KV.demo.put('todo:abc', JSON.stringify(todo));
// Retrieving an object
const raw = await platform.env.KV.demo.get('todo:abc');
const parsed = raw ? JSON.parse(raw) : null;
Namespace Patterns
Namespaces let you logically separate different types of data. Use descriptive names that reflect the purpose:
// Different namespaces for different concerns
platform.env.KV.sessions // user sessions
platform.env.KV.cache // application cache
platform.env.KV.config // configuration values
platform.env.KV.demo // demo/example data
Within a namespace, use key prefixes with a delimiter (typically :) to create a hierarchical structure:
todo:abc123 -- a specific todo item
todo:def456 -- another todo item
user:123:profile -- user profile
user:123:prefs -- user preferences
This makes prefix-based listing very effective:
// Get all todos
const todos = await platform.env.KV.demo.list({ prefix: 'todo:' });
// Get everything for user 123
const userData = await platform.env.KV.myapp.list({ prefix: 'user:123:' });
Real-World Example: Todo Application
This example is taken from the Maravilla demo application and shows a complete CRUD implementation using the KV Store.
Loading Todos
import { getPlatform } from '@maravilla-labs/platform';
const platform = getPlatform();
// List all todo keys
const res = await platform.env.KV.demo.list({ prefix: 'todo:' });
const keys = res?.keys || [];
// Fetch each todo's value
const todos = [];
for (const key of keys) {
const raw = await platform.env.KV.demo.get(key.name);
if (raw) {
try {
todos.push(typeof raw === 'string' ? JSON.parse(raw) : raw);
} catch {
// skip malformed entries
}
}
}
// Sort by creation date (newest first)
todos.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
Creating a Todo
const id = crypto.randomUUID().slice(0, 8);
const todo = {
id,
text: 'Buy groceries',
done: false,
createdAt: new Date().toISOString()
};
await platform.env.KV.demo.put(`todo:${id}`, JSON.stringify(todo));
Toggling a Todo
const raw = await platform.env.KV.demo.get(`todo:${id}`);
if (!raw) throw new Error('Todo not found');
const todo = typeof raw === 'string' ? JSON.parse(raw) : raw;
todo.done = !todo.done;
await platform.env.KV.demo.put(`todo:${id}`, JSON.stringify(todo));
Deleting a Todo
await platform.env.KV.demo.delete(`todo:${id}`);
REST API Endpoint
import { getPlatform } from '@maravilla-labs/platform';
// GET /api/todos -- list all todos
export const GET = async () => {
const platform = getPlatform();
const res = await platform.env.KV.demo.list({ prefix: 'todo:' });
const keys = res?.keys || [];
const todos = [];
for (const key of keys) {
const raw = await platform.env.KV.demo.get(key.name);
if (raw) {
todos.push(typeof raw === 'string' ? JSON.parse(raw) : raw);
}
}
return json({ todos, count: todos.length });
};
// POST /api/todos -- create a new todo
export const POST = async ({ request }) => {
const platform = getPlatform();
const body = await request.json();
const id = crypto.randomUUID().slice(0, 8);
const todo = {
id,
text: body.text.trim(),
done: false,
createdAt: new Date().toISOString()
};
await platform.env.KV.demo.put(`todo:${id}`, JSON.stringify(todo));
return json(todo, { status: 201 });
};
Limits
| Parameter | Development | Production |
|---|---|---|
| Max value size | 1 MB | 16 MB |
| Max keys per list | 1,000 | 1,000 |
| Key format | UTF-8 string | UTF-8 string |
Next Steps
- Platform Services Overview — how all three services fit together
- Database API Reference — for structured document queries
- Storage API Reference — for file and object storage