Kong: a plugin's lifecycle is a set of named phases

A custom plugin implements only the phases it needs. access runs before proxying, header_filter and body_filter shape the response, and log runs after the client has been answered.

Code
-- handler.lua
local MyPlugin = { PRIORITY = 1000, VERSION = "1.0.0" }

function MyPlugin:access(conf)
  kong.service.request.set_header("X-Tenant", conf.tenant)
end

function MyPlugin:header_filter(conf)
  kong.response.set_header("X-Handled-By", "kong")
end

function MyPlugin:log(conf)
  kong.log.info("status=", kong.response.get_status())
end

return MyPlugin
Output
Order per request:
  certificate -> rewrite -> access -> [proxy] -> header_filter
  -> body_filter (may run many times) -> log

# body_filter is called once per chunk, with the last call carrying
# ngx.arg[2] == true. Accumulating a whole body there defeats streaming and
# can exhaust memory on a large response.
#
# log runs after the response is sent, so work there costs the client nothing.
Advertisement

Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.

Published 2026-08-25