Roblox Functions in Luau: Parameters, Return Values and Scope

Last updated:

Quick answer: A Luau function is a named, reusable block of code. You declare it with local function name(params) ... end, feed it values through parameters, and get results back with return. Functions are values, so you can store them in variables and pass them to events like Touched:Connect() as callbacks.

A function in Luau is a reusable block of code that you can call by name, give inputs to (parameters), and get a result from (return values). You declare one with local function name() ... end. Functions are also regular values, which is why Roblox events accept them as callbacks.

How do I declare and call a function in Luau?

Declare the function once, then call it by writing its name followed by parentheses:

local function sayHello()
	print("Hello from a function!")
end

sayHello()
sayHello() -- run it as many times as you like

Use local function by default. A function declared without local becomes a global, which is slower and can be overwritten by any other script by accident. Functions must be declared before the line that calls them runs, so define helpers near the top of the script.

How do parameters work?

Parameters are the inputs a function receives. They behave like local variables inside the function:

local function giveCoins(player, amount)
	local leaderstats = player:FindFirstChild("leaderstats")
	local coins = leaderstats and leaderstats:FindFirstChild("Coins")
	if coins then
		coins.Value += amount
	end
end

local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
	giveCoins(player, 50) -- starter bonus
end)

If you call a function with fewer arguments than parameters, the missing ones are nil. Extra arguments are ignored. You can set a default with or:

local function spawnPart(position, color)
	color = color or Color3.fromRGB(255, 0, 0)
	local part = Instance.new("Part")
	part.Position = position
	part.Color = color
	part.Anchored = true
	part.Parent = workspace
	return part
end

spawnPart(Vector3.new(0, 10, 0)) -- red
spawnPart(Vector3.new(5, 10, 0), Color3.fromRGB(0, 170, 255)) -- blue

Luau also supports optional type annotations such as (player: Player, amount: number). They do not change how the code runs, but Studio uses them to catch mistakes while you type. They are worth adopting once the basics feel comfortable; see what is Luau.

How do return values work?

return sends a value back to whoever called the function and ends it immediately:

local function isRich(player)
	local leaderstats = player:FindFirstChild("leaderstats")
	local coins = leaderstats and leaderstats:FindFirstChild("Coins")
	if not coins then
		return false
	end
	return coins.Value >= 1000
end

if isRich(somePlayer) then
	print("Show the VIP door")
end

A function can return several values at once, which you catch in multiple variables:

local function getMinMax(numbers)
	local min, max = math.huge, -math.huge
	for _, n in ipairs(numbers) do
		min = math.min(min, n)
		max = math.max(max, n)
	end
	return min, max
end

local lowest, highest = getMinMax({ 4, 9, 2, 7 })
print(lowest, highest) -- 2 9

A function with no return gives back nil. Using that result later is a classic cause of the attempt to index nil error.

What is variable scope inside functions?

A local variable exists only in the block where you declare it. Variables defined inside a function disappear when the function ends, while the function can still read variables declared outside it:

local totalClicks = 0 -- visible to the function below

local function registerClick()
	local message = "clicked" -- only exists inside this function
	totalClicks += 1
	print(message, totalClicks)
end

registerClick() -- clicked 1
registerClick() -- clicked 2
print(message) -- nil, message is out of scope here

This is called a closure: the function remembers the outer variables it uses. It is how you keep per-part state, such as a debounce flag, without a global.

What are anonymous functions and callbacks?

A function does not need a name. You can write it inline and pass it to something that will call it later. This is exactly how Roblox events work:

local part = workspace:WaitForChild("Lava")

part.Touched:Connect(function(hit)
	local humanoid = hit.Parent:FindFirstChildOfClass("Humanoid")
	if humanoid then
		humanoid.Health = 0
	end
end)

The function inside Connect is a callback: Roblox runs it every time the part is touched, passing the touching part as the argument. You can also use a named function, which is easier to test and reuse:

local function onTouched(hit)
	print(hit.Name .. " touched the lava")
end

part.Touched:Connect(onTouched) -- note: no parentheses, you pass the function itself

Writing onTouched() with parentheses would call it right away and pass its result instead. More on this event in the Touched event guide. The same idea powers RemoteEvents and ModuleScripts, where you return a table of functions for other scripts to share.

Common mistakes with Roblox functions

Keep building

Functions are the building block for almost every system, from awarding coins to running a round. Try rewriting the coin collector from the Roblox Luau tutorial so that all the logic sits in two or three small, named functions. Small, single-purpose functions are easier to debug than one long script.

Frequently asked questions

What is the difference between a function and a method in Luau?

A method is a function stored in a table or object that receives the object itself as a hidden first argument when called with a colon, such as part:Destroy(). A plain function is called with its name, such as giveCoins(player, 10). Roblox Instances have methods like :FindFirstChild(), and in your own code you can define them with a colon on a table.

Do I need to write local before function?

Almost always yes. local function keeps the function private to the script and makes lookups faster. A global function can be overwritten by other scripts or by a typo, which creates bugs that are hard to trace. Use globals only when you intentionally want to share something, and prefer a ModuleScript for that.

Can a Luau function return more than one value?

Yes. Write return a, b, c and receive them with local x, y, z = myFunction(). If the caller has fewer variables than the function returns, the extras are dropped. Many Roblox APIs work this way; for example, workspace:Raycast returns a single result table, while pcall returns a success flag followed by the result.

Why does my function say attempt to call a nil value?

The name you are calling does not hold a function at that moment. Typical causes are a typo in the name, calling it before the local function line has run, or trying to call a method with a dot instead of a colon. Check the Output window for the line number and make sure the function is declared above where it is used.

Learn scope, local closures, varargs, and multiple returns in Luau to write reusable Roblox code.

Related pages