Storage
storage keeps small per-pack values across restarts and reloads: numbers, strings, booleans and plain tables of those. It saves to <pack>/data/storage.json shortly after each change. Saves atomically replace the file after syncing a temporary file, and preserve the previous valid value in storage.json.bak. A corrupt or unreadable store prevents the pack from loading and names the affected path; it is never silently replaced with an empty store. If recovery is needed, stop the pack, keep the damaged file for inspection, and restore the backup to storage.json.
storage.status() returns { pending: boolean, error: string? }. A write
failure remains visible and is retried. storage.flush() yields until the
current values are saved, or raises the write error. Call it from a callback
or task.spawn, after initialization. storage.set changes memory immediately;
unflushed changes can still be lost if the process crashes.
local best = storage.get("best." .. player.name) or 0if score > best then storage.set("best." .. player.name, score) endstorage.set("best." .. player.name, nil)storage.keys("best.")Strings and record keys in JSON-backed storage must be valid UTF-8; invalid
bytes raise an error instead of being replaced. Use stores.open():blob_put for
binary data. The UTF-8 rule also applies to persistent entity and block data
and other JSON-backed APIs.
A value it cannot hold is an error that names it, never a changed copy:
local t = { 1, 2 }; t.total = 3
storage.set("score", t)
-- error names score and total: mixed lists and records have no JSON shape.
storage.set("tick", function() end)
-- error: storage cannot save tick: a function is not a JSON value...
- Records use string keys; lists must be contiguous from index 1. A table cannot mix the two.
- Numbers must be finite, and cyclic tables raise an error before changing stored data.
- Persistent data views are accepted directly; reads return detached plain tables.
- Only
nildeletes.{}saves and reads back as an empty table.