The Skript book · Chapter 9

Loops

Skript has exactly three loops, and they divide the territory cleanly: repeat when you know how many times, for each when you have a list of things, and while when you know the condition to keep going. Each one takes an indented body, announces itself in the trace with ↻, and can be cut short by stop.

repeat N times

The counted loop is for fixed, known repetition:

set drumroll to ""
repeat 3 times
  add "ta-" to drumroll
add "daa!" to drumroll
log "{drumroll}"
output — real, executed at build time
▶ example.skript — Skode Skript · local simulation

  ● event: script                      → name: Demo
  ✎ set drumroll                       → = ""
  ↻ repeat 3 times                     → 
  ✎ add to drumroll                    → = "ta-"
  ✎ add to drumroll                    → = "ta-ta-"
  ✎ add to drumroll                    → = "ta-ta-ta-"
  ✎ add to drumroll                    → = "ta-ta-ta-daa!"
  • log                                → ta-ta-ta-daa!

  ✔ done in 2.1ms

repeat 1 time is accepted too — the interpreter does not make you pluralise against your grammar instincts. What the counted loop deliberately lacks is a loop counter of its own; when the body needs to know which pass it is on, keep one honestly:

set attempt to 0
repeat 3 times
  increase attempt by 1
  log "attempt number {attempt}"
output — real, executed at build time
▶ example.skript — Skode Skript · local simulation

  ● event: script                      → name: Demo
  ✎ set attempt                        → = 0
  ↻ repeat 3 times                     → 
  ✎ increase attempt                   → = 1
  • log                                → attempt number 1
  ✎ increase attempt                   → = 2
  • log                                → attempt number 2
  ✎ increase attempt                   → = 3
  • log                                → attempt number 3

  ✔ done in 2.1ms

for each, revisited

You met for each in the lists chapter; it is the workhorse of the three. One more pattern worth showing — a loop body that decides, combining iteration and branching into the shape most real automations take:

when a new lead arrives
  for each threshold in 1000, 500, 100
    if budget is at least threshold then
      log "clears the {threshold} bar"
output — real, executed at build time
▶ example.skript — Skode Skript · local simulation

  ● event: lead.created                → name: Ada Lovelace · phone: +1 555 0100 · email: [email protected]
  ↻ for each threshold in [1000, 500, 100] → 3 items
  ✗ if budget is "at least threshold"  → no
  ✗ if budget is "at least threshold"  → no
  ✗ if budget is "at least threshold"  → no

  ✔ done in 2.1ms

Note that the loop variable threshold is doing real work inside the condition — loop variables are full citizens, not just interpolation fodder.

while — and the thousand-pass promise

The condition loop keeps going as long as its condition holds:

set countdown to 5
while countdown is above 0
  log "T-minus {countdown}"
  decrease countdown by 1
log "liftoff"
output — real, executed at build time
▶ example.skript — Skode Skript · local simulation

  ● event: script                      → name: Demo
  ✎ set countdown                      → = 5
  ↻ while countdown above 0            → 
  • log                                → T-minus 5
  ✎ decrease countdown                 → = 4
  • log                                → T-minus 4
  ✎ decrease countdown                 → = 3
  • log                                → T-minus 3
  ✎ decrease countdown                 → = 2
  • log                                → T-minus 2
  ✎ decrease countdown                 → = 1
  • log                                → T-minus 1
  ✎ decrease countdown                 → = 0
  • log                                → liftoff

  ✔ done in 2.1ms

while is the one loop that can, in principle, run forever — the body above must change countdown, or the condition never fails. Every programmer alive has written that bug at least once, so Skript refuses to let it be catastrophic: a while loop is capped at 1,000 passes. This program forgets to change c; the interpreter stops it and asks exactly the question you need:

set c to 0
while c is below 5
  log "spinning"
output — real, executed at build time
✗ line 2: the "while c below 5" loop ran 1000 times — it looks infinite (does the loop change what it checks?)

This is the sandbox philosophy in one example: in a general-purpose language an infinite loop hangs the process; in an automation platform it could hang much more than that. In Skript it is a polite, specific error, and everything around it keeps running. (The trace itself has a similar guard — beyond four hundred lines it truncates its display while the program continues — so even a heavy legitimate loop cannot bury you in output.)

Choosing the right loop

A rule of thumb that has never failed anyone: say the sentence out loud first.

  • "Do this three times" → repeat 3 times
  • "Do this for each channel" → for each ch in channels
  • "Keep going while there's budget left" → while budget is above 0

If the sentence does not fall naturally into one of those shapes, the odds are excellent that you do not need a loop at all — automations mostly react once, to one event, and the loop you were about to write belongs in the platform (a segment, a broadcast, a scheduled flow) rather than in the skript. The loops are here for when the logic truly is iterative; the language just makes sure that even then, it stays legible and bounded.