---
url: /programming-fundamentals/conditionals-and-loops.md
description: Branch with if, repeat with while and for, and keep every loop safe.
---

# Conditionals and Loops

*Written: {{ $frontmatter.date }}*

## Learning objectives

* You branch with `if`, `elseif`, and `else`.
* You repeat with `while`, `repeat`-`until`, and numeric `for`.
* You stop or skip with `break` and `continue` as the last statement in their block.
* You pick the right loop for each job.
* You keep every loop safe with `task.wait`.

## Prerequisites

* Read [First Script](../getting-started/first-script.md). You can run a Script and read output.
* Read [Variables and Values](variables-and-values.md). You create and print variables.
* Read [Operators and Logic](operators-and-logic.md). You compare values and combine booleans.

## Choose a path with if

[control structures](https://create.roblox.com/docs/luau/control-structures) steer your code. An `if` statement asks a yes-or-no question and runs code only on yes. `elseif` asks a second question when the first answer was no. `else` catches everything left over. Luau reads the chain top to bottom and runs only the first branch whose condition is true.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local level = 7
if level >= 10 then
	print("Master")
elseif level >= 5 then
	print("Skilled")
else
	print("Beginner")
end
```

```txt
Skilled
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores `7` in `level`.
3. Line 3 asks "is `7 >= 10`?" The answer is false, so Luau skips line 4.
4. Line 5 asks "is `7 >= 5`?" The answer is true, so Luau runs line 6.
5. Line 6 prints `Skilled`.
6. Lines 7 to 9 close the chain. The `else` branch is skipped because a branch already ran.

Every condition here is a comparison that returns a boolean. You built those in [Operators and Logic](operators-and-logic.md). Remember that only [nil](https://create.roblox.com/docs/luau/nil) and `false` count as false. The number `0` and the empty string count as true.

## Repeat while something is true

A `while` loop repeats its body for as long as its condition stays true. It checks the condition first, so the body may run zero times. This loop fits jobs where you do not know the count up front, like counting down a timer.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local countdown = 3
while countdown > 0 do
	print(countdown)
	countdown = countdown - 1
	task.wait(0.1)
end
print("Go!")
```

```txt
3
2
1
Go!
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores `3` in `countdown`.
3. Line 3 checks `countdown > 0`. While true, the body runs.
4. Line 4 prints the current count.
5. Line 5 subtracts one so the loop moves toward its end.
6. Line 6 pauses briefly so the loop yields. You will learn why below.
7. Line 8 prints `Go!` after the loop finishes.

Line 5 subtracts one so the loop moves toward its end. Something inside the body must push the condition toward false. Without that change, the loop never ends.

## Repeat at least once with repeat-until

A `repeat`-`until` loop runs its body first and checks the condition after. The body always runs at least once. The loop stops when the condition turns true. Luau also extends visibility here: a `local` variable you declare inside the body stays visible in the `until` condition.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local total = 0
repeat
	total = total + 1
	local doubled = total * 2
	print(doubled)
	task.wait(0.1)
until doubled >= 6
```

```txt
2
4
6
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores `0` in `total`.
3. Line 3 starts the loop. There is no condition here because the check comes last.
4. Line 4 adds one to `total`.
5. Line 5 creates `doubled` from the new total.
6. Line 6 prints it.
7. Line 7 pauses briefly so the loop yields.
8. Line 8 checks `doubled >= 6`. Notice `doubled` was declared inside the loop, yet the condition can still see it. The loop repeats until this turns true.

Use `repeat`-`until` when the first run must happen no matter what, like showing a menu at least once before checking whether the player quit.

## Count exactly with numeric for

A numeric `for` loop counts from a start to an end in steps you choose. You get a counter variable that updates itself each round. This loop fits jobs where you know the count up front, like dealing five cards.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
for deal = 1, 5 do
	print(deal)
end
```

```txt
1
2
3
4
5
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 starts `deal` at `1` and repeats the body until `deal` passes `5`, adding `1` each round.
3. Line 3 prints the current counter.
4. Line 4 ends the loop body.

The step defaults to `1`. Add a third number to change it. A step of `2` counts odd numbers. A negative step counts down. The end value is included when the counter lands on it.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
for seat = 1, 5, 2 do
	print(seat)
end
for rocket = 3, 1, -1 do
	print(rocket)
end
```

```txt
1
3
5
3
2
1
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 counts `seat` from `1` to `5` in steps of `2`.
3. Line 3 prints `1`, then `3`, then `5`.
4. Line 5 counts `rocket` from `3` down to `1` in steps of `-1`.
5. Line 6 prints `3`, then `2`, then `1`.

Never assign to the counter inside the body. Luau owns the counter and resets it each round. Your assignment would be overwritten and only confuse you.

## Stop early with break and skip with continue

`break` ends a loop immediately. `continue` skips the rest of the current round and starts the next one. Both must sit as the last statement in their block. In practice that means you put each one alone inside an `if` branch, as the final line before `end`.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
for ticket = 1, 10 do
	if ticket > 3 then
		break
	end
	print(ticket)
end
```

```txt
1
2
3
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 counts `ticket` from `1` to `10`.
3. Line 3 checks whether the counter passed `3`.
4. Line 4 runs `break` as the last statement of the `if` block. The loop ends at once.
5. Line 6 prints the counter, but only for rounds that did not break.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
for ticket = 1, 5 do
	if ticket % 2 == 0 then
		continue
	end
	print(ticket)
end
```

```txt
1
3
5
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 counts `ticket` from `1` to `5`.
3. Line 3 checks for even numbers with the remainder operator.
4. Line 4 runs `continue` as the last statement of the `if` block. The `print` below is skipped for this round.
5. Line 6 prints only the odd tickets: `1`, `3`, `5`.

If strict mode complains about your `break` or `continue`, look at what follows it in the same block. Move it to the end so nothing comes after it except `end`.

## Pick the right tool

Use `if` when code runs zero or one times depending on a condition. For repeats, `while` fits an unknown number of times that may never run, `repeat`-`until` fits a body that must run at least once, and numeric `for` fits a known range. Use `break` when you found what you sought, and `continue` when some rounds deserve skipping.

## Keep loops safe with task.wait

A loop with no pause can spin thousands of times per second and freeze your game. The call `task.wait(0.1)` pauses the loop for about a tenth of a second and lets the rest of the game run. Put one inside every loop that might run long, especially `while true` loops. This pause keeps the game responsive. You use the call here as a safety pause; [Task and Async](../roblox-fundamentals/task-and-async.md) teaches the full scheduling story later.

Run this: put it in a Script in ServerScriptService and press Play, then stop the game after a few seconds.

```luau
--!strict
local ticks = 0
while true do
	ticks = ticks + 1
	print(ticks)
	task.wait(0.5)
	if ticks >= 3 then
		break
	end
end
```

```txt
1
2
3
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores `0` in `ticks`.
3. Line 3 starts an endless loop. The condition `true` never turns false by itself.
4. Line 4 adds one to `ticks`.
5. Line 5 prints the count.
6. Line 6 pauses half a second. Delete this line and the loop would spam with no pause.
7. Lines 7 to 9 break out once three rounds have printed. This `break` is your exit plan.

Every endless loop needs two things: a `task.wait` inside, and a `break` condition you can reach. Check both before you press Play.

## Common mistakes

**Writing `=` in a condition.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local level = 5
if level = 5 then
	print("ready")
end
```

```txt
Red syntax error on line 3: the script does not run until you compare with ==.
```

Conditions compare with `==`. Fix it with two equals signs. Run the fix the same way.

```luau
--!strict
local level = 5
if level == 5 then
	print("ready")
end
```

```txt
ready
```

**Forgetting to move a `while` loop toward its end.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play, then stop the game after a few seconds.

```luau
--!strict
local countdown = 3
while countdown > 0 do
	print(countdown)
	task.wait(0.1)
end
```

```txt
3
3
3
... repeats 3 forever, because countdown never changes. Stop the game.
```

This loops forever because `countdown` never changes. Fix it by updating the variable inside the body. Run the fix the same way.

```luau
--!strict
local countdown = 3
while countdown > 0 do
	print(countdown)
	countdown = countdown - 1
	task.wait(0.1)
end
```

```txt
3
2
1
```

**Putting code after `break` in the same block.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
for ticket = 1, 10 do
	if ticket > 3 then
		break
		print(ticket)
	end
end
```

```txt
Red error on line 5: break must be the last statement in its block, so the script does not run.
```

Strict mode rejects code after `break` in one block. Fix it by making `break` the last statement. Run the fix the same way.

```luau
--!strict
for ticket = 1, 10 do
	if ticket > 3 then
		break
	end
	print(ticket)
end
```

```txt
1
2
3
```

**Looping with no pause.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play, then stop the game quickly.

```luau
--!strict
while true do
	print("spin")
end
```

```txt
spin
spin
spin
... spams with no pause and freezes your game. Stop the game.
```

This freezes your game because nothing ever yields. Fix it with a wait and an exit. Run the fix the same way.

```luau
--!strict
local spins = 0
while true do
	spins = spins + 1
	print("spin")
	task.wait(0.5)
	if spins >= 2 then
		break
	end
end
```

```txt
spin
spin
```

## Exercises

Run every solution below in a Script in ServerScriptService and press Play. Try each exercise yourself before you open its solution.

1. Store a `health` value of `60`. Print `"Healthy"` when it is at least `50`, `"Hurt"` when it is at least `20`, and `"Down"` otherwise.

::: details Solution 1

```luau
--!strict
local health = 60
if health >= 50 then
	print("Healthy")
elseif health >= 20 then
	print("Hurt")
else
	print("Down")
end
```

```txt
Healthy
```

:::

2. Use a `while` loop to print `5` down to `1`, then print `"Go!"`. Include `task.wait(0.1)` in the loop.

::: details Solution 2

```luau
--!strict
local countdown = 5
while countdown > 0 do
	print(countdown)
	countdown = countdown - 1
	task.wait(0.1)
end
print("Go!")
```

```txt
5
4
3
2
1
Go!
```

:::

3. Use a numeric `for` loop to print the even numbers from `2` to `10`. Hint: step by `2` from `2`.

::: details Solution 3

```luau
--!strict
for even = 2, 10, 2 do
	print(even)
end
```

```txt
2
4
6
8
10
```

:::

4. Print tickets `1` to `8`, but skip multiples of `3` with `continue` and stop completely after printing `7` with `break`. Include `task.wait(0.1)` in the loop.

::: details Solution 4

```luau
--!strict
for ticket = 1, 8 do
	if ticket % 3 == 0 then
		continue
	end
	print(ticket)
	task.wait(0.1)
	if ticket >= 7 then
		break
	end
end
```

```txt
1
2
4
5
7
```

Line 3 skips `3` and `6`. Line 7 prints the rest. Lines 9 to 11 stop the loop after `7`, so `8` never prints.

:::

## Summary

You branched with `if`, `elseif`, and `else`. You repeated with `while` for unknown counts, `repeat`-`until` for run-at-least-once, and numeric `for` for exact counts. You stopped loops with `break` and skipped rounds with `continue`, each as the last statement in its block. You kept loops safe with `task.wait` and a reachable exit.

Next: [Functions and Scope](functions-and-scope.md).
