debug.getproto
Returns the proto (inner function) at a given index of a function.
function debug.getproto(func: function | number, index: number, active: boolean?): function | {function}Synopsis
How it works
Retrieves a nested function prototype (
Proto.p[index]) from a Luau closureClosureA function value that captures its lexical environment. In Luau, closures come in two types: LClosure (Luau bytecode + Proto + upvalues) and CClosure (native C function pointer + upvalues).. Every function defined inside another function exists as a child proto. When active is true, returns all live closures that were instantiated from that proto (searching the GC), which may be multiple closures with different upvalueUpvalueA variable captured from an enclosing scope. When a function references a local variable from an outer function, that variable becomes an upvalue — stored in an UpVal struct that persists even after the outer function returns. bindings.Proto tree — compilation model
The Luau compiler produces a tree of
Proto objects mirroring the lexical nesting of functions:
-- Source:
local function outer() -- Proto #0 (root)
local function inner_a() -- Proto #0.p[0]
local function deep() -- Proto #0.p[0].p[0]
end
end
local function inner_b() -- Proto #0.p[1]
end
end
The Proto.p[] array stores pointers to child protos. The CLOSURE bytecodeBytecodeThe compiled binary representation of Luau source code. A sequence of 32-bit instructions (opcodes + operands) stored in a Proto's code[] array. Executed by the Luau VM interpreter. instruction (CLOSURE R(A), P(Bx)) instantiates a child proto into a live LClosure by binding upvaluesUpvalueA variable captured from an enclosing scope. When a function references a local variable from an outer function, that variable becomes an upvalue — stored in an UpVal struct that persists even after the outer function returns..Active closures
When
active=true, the executor walks the GC to find all live LClosure objects whose p pointer matches the target proto. Multiple closures can exist from the same proto if the parent was called multiple times — each call creates a new closureClosureA function value that captures its lexical environment. In Luau, closures come in two types: LClosure (Luau bytecode + Proto + upvalues) and CClosure (native C function pointer + upvalues). with different upvalueUpvalueA variable captured from an enclosing scope. When a function references a local variable from an outer function, that variable becomes an upvalue — stored in an UpVal struct that persists even after the outer function returns. bindings. This is how you find the "live" copy of an inner function with actual captured state.Usage
Call an inner function
local function myFunction()
local function proto()
print("Hello, world!")
end
end
local proto = debug.getproto(myFunction, 1, true)[1]
proto() "cc">--> Hello, world!Parameters
func function | number A Luau function or stack level.
index number Index of the inner proto.
active boolean optionalIf true, returns active closures instead.
Returns
function | {function} The proto function, or list of active closures.