Codectionary / Developer documentation / Luau

Closures and captured state

A closure is a function that keeps access to locals from its surrounding scope. Each call to a factory can create independent state. Capturing a value also extends how long it stays reachable, which matters for long-lived callbacks.

Syntax

local count = 0
local function increment()
    count += 1
end

Examples

Create independent counters

Standalone Luau or a Script in ServerScriptService. Each factory call creates its own count. Calling a twice does not change b.

local function makeCounter(): () -> number
    local count = 0
    return function()
        count += 1
        return count
    end
end
local a, b = makeCounter(), makeCounter()
print(a(), a(), b()) -- 1, 2, 1

Capture a binding, not a frozen snapshot

Updating the outer local affects later calls. If a snapshot is needed, pass the value to a factory or store a separate local at the intended moment.

local multiplier = 2
local function scale(value: number): number
    return value * multiplier
end
print(scale(3)) -- 6
multiplier = 4
print(scale(3)) -- 12

Best practices

  • Keep captured state small and give it a clear owner.
  • Disconnect callbacks attached to long-lived services when their feature is removed.
  • Avoid a single shared mutable module table when each player needs independent state.

At a glance

Purpose
Typed scripting and Roblox development
File extension
.luau
Runs in
Luau host; Roblox engine examples require Roblox Studio
Usually used with
Roblox APIs and Studio

Specifications & further reading

Related Luau documentation