Perch
Building modsSettings & storage

Settings & storage

Declaring a settings page, live-apply through on_configure, and the per-mod key-value store.

2 min readUpdated Jul 21, 2026

Declaring settings

The manifest’s settings array becomes a real page in the settings rail — rendered, stored, and live-applied exactly like a builtin’s:

"settings": [
  { "key": "zone", "label": "Time zone", "kind": "text", "default": "Asia/Tokyo" },
  { "key": "h24", "label": "24-hour", "kind": "toggle", "default": true },
  { "key": "work", "label": "Work minutes", "kind": "slider",
    "min": 15, "max": 90, "default": 25 },
  { "key": "unit", "label": "Unit", "kind": "choice",
    "options": ["celsius", "fahrenheit"], "default": "celsius" }
]
KindExtra fieldsLua receives
toggleboolean
slidermin max step (default 0.01)number
choiceoptionsthe chosen option string
textstring
statusread-only display line (your logic sets it)
buttonno value — pressing it fires on_command

inline_with_previous: true joins a setting onto the previous setting’s row — compound rows like a text field with its choice chips sharing one bar.

Live-apply

function M.on_configure(host, s)
  zone, h24 = s.zone or zone, s.h24
  host.push_data("worldclock", payload())
end

on_configure fires with the full current settings table — at startup (before or right after on_start) and on every change. There is no save button and no restart anywhere in Perch; treat every change as immediate.

Storage

A mod-scoped key-value store — declare the storage scope:

perch.storage.set("history", { 3, 4, 4, 6, 9 })   -- any JSON-shaped value
local hist = perch.storage.get("history")          -- nil if absent
  • Persisted across restarts, private to your mod, capped at 64 KB total. A write that would exceed the cap is discarded — keep it for state, not data hoards.
  • Values round-trip as JSON: tables, strings, numbers, booleans. No functions, no userdata.

What goes where

DataHome
user preferencessettings (visible, user-owned)
accumulated state — histories, last-seen, countersperch.storage
live values for the viewpush_data payloads — never persisted
anything secretnowhere — mods have no secret store by design
esc
Type to search
navigate open