handler.lua holds the logic, schema.lua declares and validates the configuration, and the plugin name must be listed in kong.conf before Kong will load it.
-- kong/plugins/my-plugin/schema.lua
return {
name = "my-plugin",
fields = {
{ config = {
type = "record",
fields = {
{ tenant = { type = "string", required = true } },
{ timeout = { type = "number", default = 1000, between = { 1, 60000 } } },
},
}},
},
}
# kong.conf
plugins = bundled,my-plugin
lua_package_path = /opt/kong-plugins/?.lua;;
# Validation happens at configuration time, not at request time:
# curl -X POST localhost:8001/plugins --data name=my-plugin
# HTTP/1.1 400 Bad Request
# {"fields":{"config":{"tenant":"required field missing"}}}
#
# Check what Kong parsed from your schema:
# curl -s localhost:8001/schemas/plugins/my-plugin | jq
#
# Omitting the plugin from `plugins` in kong.conf is the usual reason a
# correctly written plugin "does not exist".
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