Beta documentation. This is an early preview — content is still in active development. Feedback helps shape the final release. Share your thoughts or join the discussion.

Configuration

These control how your Lua app behaves. Set them in your site configuration.

On this page

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() and dump() output appears in the response body
  • log.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 discarded
  • log.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.

Previous Static Files (ZIP)