Syntax
local names: {string} = {"Ada", "Zain"}
local scores: {[string]: number} = {Ada = 4}Examples
Keep an array dense
Standalone Luau or a Script in ServerScriptService. Remove the first name, append a replacement, then follow the indexes to see how the sequence changes.
local names: {string} = {"Ada", "Zain", "Jamal"}
table.remove(names, 1)
table.insert(names, "Mina")
for index, name in ipairs(names) do
print(`index {index}: {name}`)
end- Output is index 1: Zain, index 2: Jamal, then index 3: Mina. table.remove shifts the later names down; table.insert appends after the current sequence.
- {string} tells the checker that this is an array of strings. It does not change indexing: the first item is still names[1], not names[0].
- Assigning nil at index 1 would leave a hole. ipairs stops at the first absent index, and # is not a reliable item count for a table with holes.
- Change the removal index to 2. Predict the three names before running: Ada should remain first and Jamal should move into the second position.
Count dictionary entries explicitly
Count present keys independently of their order, then observe that two variables can refer to the same table.
local scores: {[string]: number} = {Ada = 4, Zain = 6}
local count = 0
for _ in pairs(scores) do
count += 1
end
local alias = scores
alias.Ada = 9
print(`Players: {count}`)
print(`Ada: {scores.Ada}`)- Output is Players: 2, then Ada: 9. The loop adds one for each present key; it does not depend on which key pairs visits first.
- The {[string]: number} annotation describes string keys and number values. #scores is not a dictionary entry count.
- alias = scores shares the original table. Updating alias.Ada therefore changes scores.Ada too; an annotation does not make assignment copy a table.
Know what table.clone leaves shared
A Luau shallow clone separates top-level fields. A nested table still belongs to both records until you copy it as well.
local original = {name = "Ada", progress = {lessons = 2}}
local copy = table.clone(original)
copy.name = "Mina"
copy.progress.lessons = 3
print(original.name)
print(original.progress.lessons)
print(original == copy)
print(original.progress == copy.progress)- Output is Ada, 3, false, then true. Changing copy.name affects only the new outer table, but both records still refer to the same progress table.
- table.clone copies the outer keys and values. When a value is itself a table, the copied value refers to that same nested table.
- Insert copy.progress = table.clone(original.progress) before updating lessons. Now the nested records are independent, and original.progress.lessons stays 2. This extra copy handles this known shape; it is not a general deep-copy algorithm.
- table.clone is a Luau library function. Do not assume a standard Lua interpreter provides it.
Best practices
- Choose sequence or dictionary operations to match the keys you actually store.
- Use table.clone only when sharing nested tables is acceptable, or copy the specific nested state that must be independent.
- A table type does not validate untrusted input. Check incoming values before using them.
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
Loops and iteration
Choose a numeric for loop for a known range, a table iterator for a collection, or a while loop for a condition. break leaves the loop and continue skips the rest of one iteration. Repeated engine work needs a schedule, not an unbounded busy loop.Functions, optional arguments and returns
Functions group a calculation or action behind a named boundary. Optional types allow nil; they do not supply defaults. Return tuples and variadic arguments are useful when the number of values matters, but named record results are often easier to extend.ModuleScripts and exported types
A ModuleScript returns a value for require to use. Keep reusable calculations in modules and choose storage based on who may require them. Requiring the same module on the client and server does not create shared memory between those environments.Luau and Roblox scripting
Start with Luau values and functions, then use Roblox Studio to connect that code to players, Instances and events. Luau is the language; Roblox supplies the game engine APIs. Codectionary supports editing and highlighting, while these Roblox examples run in Studio.
Choose a numeric for loop for a known range, a table iterator for a collection, or a while loop for a condition. break leaves the loop and continue skips the rest of one iteration. Repeated engine work needs a schedule, not an unbounded busy loop.Functions, optional arguments and returns
Functions group a calculation or action behind a named boundary. Optional types allow nil; they do not supply defaults. Return tuples and variadic arguments are useful when the number of values matters, but named record results are often easier to extend.ModuleScripts and exported types
A ModuleScript returns a value for require to use. Keep reusable calculations in modules and choose storage based on who may require them. Requiring the same module on the client and server does not create shared memory between those environments.Luau and Roblox scripting
Start with Luau values and functions, then use Roblox Studio to connect that code to players, Instances and events. Luau is the language; Roblox supplies the game engine APIs. Codectionary supports editing and highlighting, while these Roblox examples run in Studio.