Cloud saves
A save is a JSON document stored per user (called players in the API) under a slot key (slot1, profile,
settings…): a document, a user's settings, a draft, a game's progress. Saves follow the user to every device they sign in on, and each slot carries a version so two devices cannot silently
overwrite each other.
Read and write#
const save = await kumo.saves.get('slot1'); // null if the slot does not exist yet
const state = save?.data ?? { level: 1, hp: 3 };
state.level += 1;
await kumo.saves.set('slot1', state); // last write wins| Method | Returns |
|---|---|
saves.get(key) | { key, version, size, updatedAt, data } or null |
saves.set(key, data, { ifVersion? }) | { key, version, size, updatedAt } |
saves.list() | [{ key, version, size, updatedAt }] (no data) |
saves.delete(key, { ifVersion? }) | — |
Conflict-safe writes#
The simple form overwrites. When a user might use two devices at once, write with ifVersion:
try {
await kumo.saves.set('profile', profile, { ifVersion: 'latest' });
} catch (e) {
if (e.code !== 'version_conflict') throw e;
const cloud = await kumo.saves.get('profile'); // someone else wrote first
profile = merge(cloud.data, profile); // your app decides how to merge
await kumo.saves.set('profile', profile, { ifVersion: cloud.version });
}ifVersion: 'latest'— the version this SDK instance last saw for that slot (0 if it never read it)ifVersion: <number>— write only if the stored version equals it;0means "only if the slot does not exist"- On mismatch the server answers 409
version_conflictwithdetails.currentVersion
Limits#
| Limit | Value |
|---|---|
| Slots per user | 32 (too_many_saves) |
| Size per slot | 256 KB of JSON (save_too_large, HTTP 413, with details.size and details.limit). The SDK counts the bytes before sending and throws the same error without sending; a raw HTTP body over 1 MB gets 413 invalid_request |
| Slot key | lowercase snake_case: starts with a letter, then a-z, 0-9, _; up to 48 characters |
Saves are scoped to the environment: development saves never appear in production.
Saves or your own database?#
The user's own browser writes saves, so a modified page can put anything in them. Pick by who may change the data:
Protect in D1, not in saves. Anything a user must not be able to change themselves — scores and rankings, coins, credits, items, purchases, badges, anything shared between users — goes in the project's own Functions + D1. saves holds only what the user may freely write (settings, drafts, a solo game's progress).
| Put it in | What | Who writes it |
|---|---|---|
| Saves | what the user may change freely: settings, progress notes, drafts, favorites, a game's save | the user's browser (a changed value hurts nobody) |
| Your database in Functions (D1) | what must be protected: scores and rankings, coins, credits, items, purchases, a verified badge, anything shared between users | only your server code |
When unsure: if a user changing it by hand would be a problem, keep it in your database. Saves hold state, not currency. Your server code cannot read or write a user's saves, so keep the protected copy in your database from the start.