Control Flow in Lua: if, for, while, and repeat

· 4 min read · Updated March 17, 2026 · beginner
control-flow if-statement loops beginner fundamentals

Control flow statements are the backbone of any programming language. They let your program make decisions, repeat actions, and handle different conditions. In this tutorial, you’ll learn every control flow mechanism Lua offers.

This is the third tutorial in our Lua fundamentals series. If you’re new to Lua, start with our earlier tutorials on installing Lua and working with variables.

The if Statement

The if statement is the most fundamental control structure. It executes a block of code only when a condition evaluates to true.

local temperature = 25

if temperature > 30 then
    print("It's hot outside!")
end

The condition after if must evaluate to a boolean value. In Lua, only nil and false are falsy—everything else is truthy, including 0 and empty strings.

if-elseif-else Chains

For more complex decision-making, use elseif and else:

local score = 85

if score >= 90 then
    print("Grade: A")
elseif score >= 80 then
    print("Grade: B")
elseif score >= 70 then
    print("Grade: C")
else
    print("Grade: F")
end

You can chain as many elseif blocks as needed. Lua evaluates them top-to-bottom and stops at the first true condition.

Numeric for Loops

The numeric for loop runs a specific number of times:

-- Print numbers 1 to 5
for i = 1, 5 do
    print(i)
end

-- With step value
for i = 10, 0, -2 do
    print(i)  -- Prints: 10, 8, 6, 4, 2, 0
end

The syntax is for var = start, end, [step] do. The step defaults to 1 if omitted.

Generic for Loops

Generic for works with iterators, commonly used to iterate over tables:

local fruits = {apple = 1, banana = 2, cherry = 3}

-- Iterate over key-value pairs
for key, value in pairs(fruits) do
    print(key, value)
end

-- Iterate over array-like tables
local colors = {"red", "green", "blue"}
for index, color in ipairs(colors) do
    print(index, color)
end

Use pairs() for arbitrary key-value iteration and ipairs() for sequential array-style iteration.

While Loops

A while loop repeats as long as its condition remains true:

local count = 1

while count <= 5 do
    print(count)
    count = count + 1
end

Be careful—unlike for loops, while loops can create infinite loops if the condition never becomes false.

repeat…until Loops

The repeat...until loop executes at least once, then checks its condition:

local input

repeat
    print("Enter quit to exit")
    input = io.read()
until input == "quit"

print("Goodbye!")

This is useful when you need to prompt for input before validating.

Breaking and Continuing

Use break to exit a loop immediately:

for i = 1, 10 do
    if i == 5 then
        break
    end
    print(i)
end
-- Prints: 1, 2, 3, 4

Lua doesn’t have a continue statement. Instead, nest your condition or use a flag variable.

Nested Control Flow

You can nest control structures inside each other:

local matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
}

for i = 1, #matrix do
    for j = 1, #matrix[i] do
        if matrix[i][j] % 2 == 0 then
            print("Even:", matrix[i][j])
        end
    end
end

Practical Example

Here’s a simple number guessing game combining everything:

local target = math.random(1, 10)
local attempts = 0
local guess

print("Guess a number between 1 and 10")

repeat
    attempts = attempts + 1
    io.write("Your guess: ")
    guess = tonumber(io.read())
    
    if guess < target then
        print("Too low!")
    elseif guess > target then
        print("Too high!")
    end
until guess == target

print("Correct! It took you " .. attempts .. " attempts.")

Understanding Truthiness

Lua’s truthiness is simple but powerful. Only nil and false are falsy—everything else is truthy, including zero, empty strings, and even empty tables. This affects how conditions evaluate:

local value = 0

if value then
    print("Truthy!")  -- This prints because 0 is truthy
end

if value ~= nil then
    print("Not nil!")  -- This also prints
end

This behavior differs from languages like Python or JavaScript. Understanding it prevents subtle bugs, especially when checking for missing values.

Common Pitfalls

Several mistakes trip up newcomers to Lua:

Forgetting the then keyword:

-- Wrong
if temperature > 30
    print("Hot")

-- Correct
if temperature > 30 then
    print("Hot")
end

Off-by-one errors in numeric for loops:

-- This prints 1 to 4, not 1 to 5
for i = 1, 5 - 1 do
    print(i)
end

Infinite while loops:

-- Bug: count never changes
local count = 1
while count <= 5 do
    print(count)
    -- Missing: count = count + 1
end

Choosing the Right Loop

Different loops suit different situations:

  • Use numeric for when you know the exact iteration count
  • Use generic for when iterating over tables or custom iterators
  • Use while when the loop condition depends on dynamic values
  • Use repeat…until when you need the body to execute at least once

Choosing correctly makes your code clearer and less error-prone.

Summary

Lua provides straightforward control flow mechanisms:

  • if — Execute code conditionally
  • elseif — Additional conditions
  • else — Fallback code when all conditions are false
  • for — Numeric and generic iteration
  • while — Loop while condition is true
  • repeat...until — Loop until condition is true (always runs at least once)
  • break — Exit a loop early

These building blocks let you create complex programs. Master them, and you’ll be writing Lua with confidence.