Skip to content
lantern.

Persistent site storage.

Keep data across requests with ctx.read and ctx.write, instead of global variables.

On this page

A complete persistent counter.

GET reads the counter without changing it. POST /increment saves the next value, then redirects to / so the browser displays the updated page. Try it in preview and again after reopening the site. Local preview uses the local site’s real data, so preview form submissions can change that data.

app.lua
return function(ctx)  local P = ctx.page  local count = ctx.read("counter", 0)  if ctx.method == "POST" and ctx.path == "/increment" then    ctx.write("counter", count + 1)    return {kind="redirect", path="/"}  end  if ctx.method ~= "GET" or ctx.path ~= "/" then    return {kind="error", status=404, message="Page not found"}  end  return {kind="page", page=P.document("Community counter", {    P.heading{text="Count: " .. tostring(count)},    P.form{action="/increment", children={P.submit{text="Add one"}}}  })}end

Keys and values.

For portability, use storage keys of 2–40 lowercase letters, digits or hyphens, beginning with a letter or digit. The cloud accepts a somewhat broader key set; local hosts use the stricter site-name rule.

Store strings, booleans, numbers and JSON-compatible tables. Do not store functions, cyclic structures or host objects. ctx.read(key, default) returns default when the key is absent. ctx.write is allowed only on POST requests. There is no dedicated delete-key API.

Where the data lives.

Publishing code does not migrate your local data. Test with disposable data and plan any real migration separately. Keep local backups of your site folder and protect private identity state separately.

Local hostLantern Hub
/lantern-data/sites/<name>/data/<key>.jsonSite-scoped cloud database storage
Stored on the Minecraft computerSurvives fresh execution VMs
Excluded from Upload Hub draftNot copied from local preview storage

Concurrency and limits.

The current cloud site storage limit is 128 KiB. Conflicting concurrent writes are rejected rather than silently overwriting one another. The counter is a teaching example, not a transactional high-traffic counter service. Reload and inspect state before resubmitting a conflicting action.

Keep guestbooks and lists bounded. The guestbook template retains a limited number of entries. Data is scoped to a site, but any visitor can invoke routes you expose; your handler is responsible for what those routes allow.

Found a mismatch? Include the exact error, runtime version and a small example with secrets removed.