Skip to content
lantern.

Server-side Lua.

Handle a request, build a page, and return a response. Start with a complete working file.

On this page

The handler contract.

The file must return a function. Lantern calls that function with ctx for each request. The function returns page data, a redirect, an error, or nil for static fallback.

local P = ctx.page is simply a convenient abbreviation. P.document adds the document version and title; P.paragraph, P.heading and other builders add the component type. They do not print or draw directly.

app.lua
return function(ctx)  local P = ctx.page  return {kind="page", page=P.document("My first site", {    P.heading{text="Hello, other worlds!"},    P.paragraph{text="testing"},    P.link{text="Explore the Hub", href="hub://directory/"}  })}end

Request context.

MemberMeaning
ctx.methodGET for navigation; POST for forms
ctx.pathRooted site path, such as / or /greet
ctx.fieldsSubmitted string or boolean field values
ctx.requestIdRequest identifier, not a secret or user identity
ctx.page.document(title, children)Build a version-1 page
ctx.page.<component>{...}Build any documented component
ctx.read(key, default)Read persistent site data
ctx.write(key, value)Write JSON-compatible site data on POST

Response types.

Alternative return statements
-- Render a documentreturn {kind="page", page=P.document("Title", {P.paragraph{text="Hello"}})} -- Navigate within this sitereturn {kind="redirect", path="/"} -- Report an input or route errorreturn {kind="error", status=400, message="Please enter a name"} -- Fall back to a static JSON file on GETreturn nil

Route before doing work.

Test both ctx.method and ctx.path before handling a form. Return nil for static GET fallback, or an explicit 404 error for unknown routes. Do not change data merely because someone opens a page.

Available cloud Lua functions.

The environment exposes assert, error, ipairs, pairs, next, pcall, select, tonumber, tostring and type, plus math, string, table and utf8. It does not expose print, os, io, shell, fs, http, peripheral, require, package, load or debug. There is no arbitrary network access.

Every cloud request starts fresh. Variables and globals from an earlier request are gone. Local hosts use the installed computer’s Lua environment and privileges, so local success does not prove cloud compatibility. Use only the shared ctx API for portable handlers.

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