Roblox Luau tables hold related values behind keys. Use an array-style table when order matters, such as a route of checkpoint names. Use dictionary-style keys when each value has a named role, such as a round’s configuration. The important design choice is how callers will find and update the data.

Choose an ordered list or named keys
Roblox’s tables guide covers arrays and dictionaries, including one-based array indexing. The first ordinary array entry is at index 1. A dictionary lets you choose meaningful keys instead of relying on a position’s meaning.
| Design | Example lookup | Question it answers |
|---|---|---|
| Ordered route | route[2] | What is the second checkpoint? |
| Named settings | settings.enabled | Is this configuration enabled? |
| Dynamic named key | settings[key] | Which setting does this variable identify? |
Write down the lookup your consumer needs before building a large table. A position is useful for an ordered route. A stable name is often clearer for a configuration value that should not change meaning when another field is added.
Run a complete list, dictionary, and reference exercise
Insert a regular Script in ServerScriptService in a practice place. Open Output and run the following code. It changes local tables and prints results; it does not modify actual checkpoint objects, players, or saved progress.
local route = {"Start", "Bridge", "Finish"}
table.insert(route, 2, "Garden")
local removed = table.remove(route, 3)
print("Removed:", removed)
print("Route length:", #route)
for index, name in ipairs(route) do
print(index, name)
end
local settings = {
roundName = "Garden Run",
enabled = false,
}
print("Enabled before:", settings.enabled)
settings.enabled = true
settings.note = "Practice only"
settings.note = nil
local entryCount = 0
for _ in pairs(settings) do
entryCount += 1
end
print("Enabled after:", settings.enabled)
print("Note removed:", settings.note == nil)
print("Setting entries:", entryCount)
local alias = route
alias[2] = "Tower"
print("Original route changed:", route[2])
local original = {theme = {name = "Blue"}}
local shallow = table.clone(original)
shallow.theme.name = "Green"
print("Shared nested value:", original.theme.name)
shallow.theme = {name = "Orange"}
print("Original nested value remains:", original.theme.name)
The intended result removes Bridge, reports route length 3, and lists Start, Garden, Finish at indices 1 through 3. The settings section changes enabled from false to true, confirms note was removed, and counts two remaining entries.
The reference examples then show Tower through the original route variable, Green through the original nested table, and Green again after the clone receives a replacement nested table. These are predicted values from the code, not captured Studio output. The example has been documentation-reviewed but has not been executed here inside Studio.
Insert and remove without losing the intended order
In the example, inserting Garden at index 2 shifts the following route entries. Removing index 3 then removes Bridge and closes that position. Trace the indices after each operation rather than assuming an object’s old position remains its identity.
A checkpoint name and its current array position are different things. If another system needs a stable identifier, do not silently use the position as that identifier while allowing the list to be reordered. Decide whether consumers should follow the current sequence or retain a particular checkpoint identity.
For a compact list, use intentional array operations rather than deleting a middle entry with nil. A hole changes what a contiguous sequence means and can make a loop or length-based operation do something different from the list you imagined.
Use the right loop for the data shape
The Luau standard library documents ipairs as sequential numeric traversal that stops at the first nil. It is useful for the compact route in this exercise. pairs visits entries without promising the named-key order you might expect from their written appearance.
That is why the dictionary loop counts entries without printing an exact expected key sequence. If a UI needs settings in a chosen order, represent that order deliberately instead of relying on whichever key is visited first.
Modern Luau also supports generalized table iteration, as shown in the Roblox guide. Read unfamiliar examples by checking their actual table shape and ordering requirements rather than assuming every for loop describes an ordered array.
Do not use array length as a dictionary entry count
The route is a compact sequence, so #route is useful here. The settings table has named keys, and this exercise counts them explicitly with a loop. Keep the meaning of “length” tied to your data design rather than treating every table as a numbered list.
For a mixed table, separate questions that may otherwise become confused: how many ordered items are in the sequence, and how many keyed entries exist overall? A clearer representation may be two separate tables instead of one structure with several unrelated responsibilities.
False is stored data; nil removes an entry
The settings table begins with an explicit false value. That is still a configuration entry. The note assignment to nil removes the note entry instead. Check whether you need “disabled” and “not configured” to mean different things.
For example, a defaulting rule that treats every false value as missing can accidentally override an intentional choice. Use explicit checks when the distinction matters. The Boolean guide develops that idea with small conditions you can inspect.
Assignment shares a reference; cloning is shallow
Assigning route to alias does not create a separate route. The later write through alias appears when reading route. The library’s table.clone operation makes a shallow copy: the outer table is copied, while its nested table references still identify the same nested objects.
The final exercise makes that visible in two steps. Changing shallow.theme.name changes the shared nested object. Replacing shallow.theme changes an entry on the cloned outer table, so it leaves original.theme pointing at the earlier nested table.
Do not call this an independent deep copy. If your feature needs one, define the supported value types, nested structure, and handling of shared references before choosing a copying strategy. A small flat configuration may be easier to reason about than a deeply nested structure.
Keep in-memory tables separate from saved or replicated data
A local table in this exercise is temporary program state. It is not automatically an object in Explorer, a shared server/client table, or persistent player progress. Decide which lifetime and communication boundary a feature actually needs.
For reusable APIs and constructor-created instances, continue with the ModuleScript guide. For values attached to Instances, use the attributes exercise. For a controller finding several objects, see CollectionService. For safely selecting an array entry, continue with the math.random and random-choice guide. Documentation checked November 8, 2026.


