Lua syntax - specifically for Roblox
Core syntax
-- single-line comment
--[[ multi-line
comment ]]
local name = "Damir" -- always use `local`, otherwise it's global
local health = 100
local isAlive = true
local nothing = nil -- like None/null
print(name, health) -- Roblox prints to the Output windowTypes: nil, boolean, number (one type for ints and floats), string, table, function, plus Roblox types like Vector3, CFrame, Instance.
Operators that differ from what you're used to:
print("a" .. "b") -- string concat is ..
print(10 // 3) -- floor division → 3
print(2 ^ 3) -- power → 8
print(5 ~= 4) -- not equal is ~=
print(not true, true and false, true or false)
print(#"hello") -- length operator → 5Control flow
if health > 50 then
print("healthy")
elseif health > 0 then
print("hurt")
else
print("dead")
end
for i = 1, 5 do -- inclusive: 1,2,3,4,5
print(i)
end
for i = 10, 1, -2 do end -- with step
local n = 0
while n < 3 do
n += 1 -- compound assignment works in Luau (Roblox)
endNote: only nil and false are falsy. 0 and "" are truthy.
Functions
local function add(a, b)
return a + b
end
local greet = function(who)
return "Hello, " .. who
end
-- multiple return values
local function minMax(a, b)
return math.min(a, b), math.max(a, b)
end
local lo, hi = minMax(3, 9)Tables (arrays, dicts, objects, all in one)
-- array (1-indexed!)
local items = {"sword", "shield", "potion"}
print(items[1]) -- "sword"
table.insert(items, "bow")
table.remove(items, 2)
print(#items)
-- dictionary
local player = {name = "Damir", level = 5}
player.level += 1
player["gold"] = 250
-- iterate
for i, item in ipairs(items) do -- arrays, in order
print(i, item)
end
for key, value in pairs(player) do -- dictionaries, unordered
print(key, value)
endGotcha: arrays start at 1, not 0.
Tables as classes (OOP)
local Enemy = {}
Enemy.__index = Enemy
function Enemy.new(name, hp)
local self = setmetatable({}, Enemy)
self.name = name
self.hp = hp
return self
end
function Enemy:takeDamage(amount) -- colon passes `self` automatically
self.hp -= amount
if self.hp <= 0 then
print(self.name .. " died")
end
end
local goblin = Enemy.new("Goblin", 30)
goblin:takeDamage(40)Roblox specifics
Services: get built-in systems via game:GetService.
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")Instances and the hierarchy:
local part = Instance.new("Part")
part.Size = Vector3.new(4, 1, 4)
part.Position = Vector3.new(0, 10, 0)
part.BrickColor = BrickColor.new("Bright red")
part.Anchored = true
part.Parent = workspace -- setting Parent is what makes it appear
local child = workspace:FindFirstChild("SpawnPoint")
local waited = workspace:WaitForChild("Map") -- yields until it existsEvents (the core of Roblox scripting):
part.Touched:Connect(function(otherPart)
local humanoid = otherPart.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health -= 25
end
end)
Players.PlayerAdded:Connect(function(player)
print(player.Name .. " joined")
end)Waiting and loops:
task.wait(1) -- use task.wait, not the old wait()
task.spawn(function() ... end)
task.delay(5, function() print("5s later") end)
RunService.Heartbeat:Connect(function(dt)
-- runs every frame; dt = seconds since last frame
end)Script types
| Type | Runs on | Lives in | Use for |
|---|---|---|---|
Script | Server | ServerScriptService / Workspace | game logic, data, security |
LocalScript | Client | StarterPlayerScripts, StarterGui | UI, input, camera |
ModuleScript | Whoever requires it | ReplicatedStorage / ServerStorage | shared code |
-- ModuleScript
local Utils = {}
function Utils.double(x) return x * 2 end
return Utils
-- another script
local Utils = require(game.ReplicatedStorage.Utils)
print(Utils.double(4))Client ↔ Server: RemoteEvents
Clients can't be trusted, so the server does the real work and the client only asks.
-- LocalScript
local remote = game.ReplicatedStorage:WaitForChild("BuyItem")
remote:FireServer("Sword")
-- Script
local remote = game.ReplicatedStorage.BuyItem
remote.OnServerEvent:Connect(function(player, itemName)
-- validate itemName and check player's gold here!
end)Luau extras (Roblox's Lua dialect)
--!strict
local function heal(hp: number, amount: number): number
return math.min(hp + amount, 100)
end
type Item = {name: string, price: number}Optional type annotations give you autocomplete and error checking in Studio.
Common mistakes to avoid
- Forgetting
local→ accidental globals - Using
0as the first index - Forgetting
.Parent = ...so the part never shows up - Trusting values sent from the client
- Using
wait()instead oftask.wait()