ACTIAS

How a request runs

Each request builds a fresh Lua environment, runs your handler, and discards it.

One environment per request

Nothing survives in memory between requests.

local seen = 0

on "fetch" (function(request)
    seen = seen + 1
    return { body = tostring(seen) }   -- always "1"
end)

Each request gets its own copy of the script's state. Nothing is shared between requests, and nothing needs cleaning up after one finishes.

Compiled code is shared, and the environment is built ahead: the platform keeps a few fresh ones per revision, each having run the top level once and served nothing, so a request takes one rather than building it. A top-level value such as os.time() or a secret was read when the environment was built, at most 30 seconds earlier.

Anything you need to keep goes in kv, a database, or an object.

The top level runs once

Code outside your handler runs when the environment is built. That is where declarations go:

local visits = kv "visits"
local db = database "catalog" { migrations = "migrations/catalog" }

on "fetch" (function(request)
    -- handler body
end)

Declarations are only valid at the top level. To collect them the platform runs your entry point with every effectful surface stubbed out, so it derives the contract without executing a single handler.

Request and response

The handler takes a request table and returns a response table.

on "fetch" (function(request)
    if request.method == "POST" and request.path == "/api/echo" then
        return {
            status_code = 200,
            headers = { ["content-type"] = "application/json" },
            body = request.body,
        }
    end
    return { status_code = 404, body = "no such route" }
end)

request.path is relative to your script: one served at /hello/ sees /api/echo, not /hello/api/echo. request.query is a decoded table. Every field is in the http reference.

Budget

A request is bounded by work, not by time: waiting on io costs nothing, computing costs. The ceiling is about a second of solid computation, which no ordinary handler comes near.

BoundValueCovers
work budget5,000,000 work unitscomputation in the vm
wall backstop10 secondscode stuck inside a host call that never returns to the vm
request deadline30 secondsthe whole request, waiting included
request body10 MBlarger bodies are refused with 413

Work that does not fit belongs in a queue or a workflow.

Gotchas

  • Top-level state looks like a cache and is not one. The counter above resets on every request, including in production.
  • Work at the top level is paid on every request, since the environment is rebuilt each time. Put it in the handler.
  • kv "visits" inside a handler is an error, not a late declaration. The declaration forms are top level only.