Environment variables
These control how your Lua app behaves. Set them in your site configuration.
| Variable | Default | What it does |
|---|---|---|
APP_DEBUG |
false |
Enable detailed error messages, stack traces, and log.debug() output |
LOG_ENABLED |
true |
Write log entries to disk |
LOG_MAX_BYTES |
5242880 |
Max log file size (5MB). Exceeded → renamed to .old, new file started |
Debug mode (APP_DEBUG=true)
In production, keep this off. Errors show a generic message. In development, turn it on:
With APP_DEBUG=true:
- Stack traces appear in error responses
print()anddump()output appears in the response bodylog.debug()actually writes to the log file- Template errors show the exact line that failed
With APP_DEBUG=false (production):
- Errors return generic messages (no internals exposed)
print()/dump()silently discardedlog.debug()calls are zero-cost (no I/O)
-- Only do expensive debug work if needed
if log.should_debug() then
log.debug("Complex state: " .. encoder.json(large_table))
end
Logging
Logs go to storage/logs/site_{id}.log. Each entry is a JSON line:
[2026-05-25T15:30:00.000+00:00] lua.INFO: User logged in {"site":82468,"method":"GET","path":"/"} []
Log levels
log.info("User " .. user_id .. " created a post") -- always written
log.warn("Rate limit at 90% for IP " .. env.remote_ip) -- always written
log.error("Payment failed: " .. reason) -- always written
log.debug("Variable x = " .. tostring(x)) -- only when APP_DEBUG=true
Check before debugging
log.should_debug() returns true only when APP_DEBUG=true. Use it to skip expensive debug computations:
if log.should_debug() then
-- Only serialize this large table in debug mode
log.debug(encoder.json(some_huge_table))
end
Log rotation
When LOG_MAX_BYTES is exceeded, the current log is renamed to site_{id}.log.old and a new file starts. Old logs are not automatically deleted — clean them up periodically.
Dry run mode
The framework has a dry run mode for testing. Check with _framework.is_dry_run():
if _framework.is_dry_run() then
return { preview = true }
end
This is mainly for internal tooling — you usually won't need it.
Controlling auto-run
By default, Wapka automatically calls app:run() after your lua_init code finishes. You can disable this:
local app = framework()
app:auto_run(false) -- manual control
-- ... define routes ...
app:run() -- call explicitly when ready
When auto_run is false, you must call app:run() yourself. This is useful when you need to load modules or set up helpers before the request is dispatched.
Debug tracing
Add ?__trace=1 to any URL to get a full execution trace. This shows every step the engine took — libraries loaded, globals set, middleware run, route matched, handler called — all as structured data.
https://yoursite.wapka.site/?__trace=1
Great for debugging complex issues. Works only when APP_DEBUG=true.
Quick reference
log.info("message") -- always writes
log.error("message") -- always writes
log.warn("message") -- always writes
log.debug("message") -- only APP_DEBUG=true
log.should_debug() -- true if APP_DEBUG=true
_framework.is_dry_run() -- true in dry run mode
_framework.env_debug() -- true if APP_DEBUG=true
app:auto_run(false) -- disable auto-run
Next: Explore the Twig Templates guide to build HTML pages.