LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 618 min read

Control Flow

Learn Lua's if/elseif/else, while and repeat/until loops, numeric and generic for loops, and how Lua handles branching without a switch statement.

Introduction

Lua's control flow will feel immediately familiar if you've used any C-family or Pascal-family language, with a few Lua-specific quirks worth knowing up front — most notably, there is no switch statement and, until recently, no continue keyword.

What You Will Learn
  • Lua's if/elseif/else syntax and how blocks end with end.
  • while and repeat/until loops, and the difference between them.
  • Numeric and generic for loops, including how they interact with tables from lesson 5.
  • Why Lua has no switch statement, and how to get the same result with a table.

if, elseif, else

Every block in Lua — if, loops, functions — closes with the end keyword instead of curly braces.

local score = 72
if score >= 90 then
print("Grade: A")
elseif score >= 75 then
print("Grade: B")
elseif score >= 60 then
print("Grade: C")
else
print("Grade: F")
end
Output

Click Run to see what this code prints.

while and repeat/until Loops

while checks its condition before each iteration, exactly like most languages. repeat/until is Lua's equivalent of a "do-while" loop — the body always runs at least once, and the loop continues until (not while) the condition becomes true.

local count = 1
while count <= 3 do
print("while:", count)
count = count + 1
end
local n = 1
repeat
print("repeat:", n)
n = n + 1
until n > 3
Output

Click Run to see what this code prints.

The Numeric for Loop

The numeric for loop takes a start, a stop, and an optional step, and is the idiomatic way to count through a range of numbers.

for i = 1, 5 do
print(i)
end
print("--")
for i = 10, 0, -2 do -- start, stop, step (counts down by 2)
print(i)
end
Output

Click Run to see what this code prints.

The Generic for Loop

The generic for loop, seen already in lesson 5 with pairs() and ipairs(), works with any iterator function — it is the standard way to walk through a table's contents.

local colors = {"red", "green", "blue"}
for index, value in ipairs(colors) do
print(index, value)
end
Output

Click Run to see what this code prints.

break and No continue

break exits a loop immediately, just like in most C-family languages. Lua has no dedicated continue keyword — the idiomatic workaround is to wrap the rest of the loop body in an if, or (in Lua 5.2+) use goto to jump to a label at the end of the loop.

-- "continue" via an if-wrapped body
for i = 1, 5 do
if i % 2 == 0 then
goto continue
end
print("odd:", i)
::continue::
end
Output

Click Run to see what this code prints.

No switch Statement

Lua has no built-in switch statement. The idiomatic replacement uses a table mapping cases to functions (or values) — leaning directly on tables and first-class functions from earlier lessons instead of adding new syntax.

local actions = {
start = function() print("Starting...") end,
stop = function() print("Stopping...") end,
pause = function() print("Pausing...") end,
}
local command = "stop"
local action = actions[command]
if action then
action()
else
print("Unknown command: " .. command)
end
Output

Click Run to see what this code prints.

Common Mistakes

Avoid These Mistakes
  • Forgetting then after if/elseif conditions, or do after while/for — both are required, unlike some C-family languages.
  • Reaching for a long elseif chain when a table-dispatch pattern (shown above) would be clearer for many cases.
  • Expecting a continue keyword to exist — use an if-wrapped body or goto ::continue:: instead.

Best Practices

  • Prefer the numeric for loop for counting ranges, and the generic for with ipairs()/pairs() for tables.
  • Use table-dispatch instead of a long if/elseif chain once you have more than a handful of cases.
  • Reach for goto sparingly — it exists mainly for the continue workaround and breaking out of nested loops, not general control flow.

Frequently Asked Questions

It's a design choice inherited from Lua's Pascal-influenced roots — every block (if, loops, functions) closes explicitly with end rather than {}.

Yes, for an array-style table use a numeric for loop counting down: for i = #t, 1, -1 do ... end.

Used narrowly (like the continue pattern shown above, or breaking out of deeply nested loops) it's considered idiomatic; using it for general control flow is discouraged the same as in most other languages.

Key Takeaways

  • Every Lua block ends with end; if needs then, while/for need do.
  • repeat/until runs its body at least once and loops until the condition becomes true.
  • The numeric for loop takes start, stop, and an optional step.
  • Lua has no switch statement or continue keyword — table dispatch and goto ::label:: are the idiomatic replacements.

Summary

You can now branch and loop through Lua code confidently, including the two features (no switch, no continue) that surprise newcomers most. Next, you'll cover functions — first-class values in Lua, capable of multiple return values and variable argument lists.

Next Lesson →

Functions