If you’ve spent any time writing AL, you’ve probably written the same pattern dozens of times: loop through records, check a condition, and either skip the row or wrap the rest of the body inside a big if block. It works, but the indentation creeps up fast, and the intent gets buried.
The continue statement gives us a cleaner way to do that. It’s a small addition to the language, but it’s one of those quality-of-life improvements that make loops noticeably easier to read.

What Is the continue Statement?
continue skips the rest of the current iteration of a loop and jumps straight to the next one. The loop itself keeps running—only the remaining statements in the current pass are bypassed.
It works inside the usual AL loop constructs:
repeat ... untilwhile ... dofor ... doforeach ... in ... do
Think of it as the counterpart to break. Where break exits the loop entirely, continue just says “I’m done with this one—move on.”
Why You Should Care
- Flattens deeply nested
ifblocks inside loops - Makes filter/skip logic read top-to-bottom instead of inside-out
- Reduces indentation, which tends to reduce bugs
- Matches the pattern that developers coming from C#, JavaScript, and most other languages already expect
How It Works
A few things worth knowing before you sprinkle continue everywhere:
continueonly affects the innermost loop it appears in. If you’re inside a nested loop, it won’t skip the outer loop’s iteration.- In a
repeat ... untilblock over a record, you still needNext()to advance the cursor.continuedoes not callNext()for you—but becauseNext()is part of the loop condition pattern (e.g.,until Customer.Next() = 0), the loop still moves forward correctly when you use it the typical way. continueoutside of a loop is a compile error.- It’s available in recent runtime versions of AL (rolled out as part of the 2025 release waves), so make sure your project’s runtime target supports it before using it.
Before: The Nested if Pattern
Here’s the kind of code we’ve all written. We want to process customer payments, but skip those that are blocked or have no balance.
if Customer.FindSet() then
repeat
if not Customer.Blocked then begin
Customer.CalcFields("Balance (LCY)");
if Customer."Balance (LCY)" <> 0 then begin
// ... do the actual work here ...
ProcessCustomer(Customer);
end;
end;
until Customer.Next() = 0;
It works, but the meaningful line—ProcessCustomer(Customer)—is buried two levels deep. Add another condition, and you’re fighting the indentation.
What About break?
A quick reminder, since the two often get mentioned in the same breath: break is not a replacement for continue. break exits the loop entirely—the moment it runs, the loop is done and execution moves on to whatever comes after the until (or end). It’s the right tool when you’ve found what you were looking for and there’s no reason to keep iterating, but it’s the wrong tool when you just want to skip the current row.
// `break` stops the whole loop after the first match.
if Customer.FindSet() then
repeat
if Customer."No." = 'C00010' then begin
ProcessCustomer(Customer);
break; // we're done — don't look at any more customers
end;
until Customer.Next() = 0;
Before continue existed, there was no clean equivalent. If you wanted to skip a single iteration, you really had two choices:
- Wrap the loop body in nested
ifblocks (the “Before” example above). - Extract the body into a procedure and
exitearly from that procedure when a guard condition is hit.
The procedure trick worked, but felt heavy for what should be a one-line “skip this row” decision. continue finally gives us that one-liner.
After: The continue Version
Same logic, rewritten with continue:
if Customer.FindSet() then
repeat
if Customer.Blocked.AsInteger() <> 0 then
continue;
Customer.CalcFields("Balance (LCY)");
if Customer."Balance (LCY)" = 0 then
continue;
// The actual work is now at the top level of the loop body.
ProcessCustomer(Customer);
until Customer.Next() = 0;
The “skip” rules are listed up front, each one reads as a single sentence, and the real work lives at the natural indentation level. This is the pattern I reach for most often.
continue in Other Loop Types
It works the same way in foreach and for:
foreach Item in ItemList do begin
if Item.Blocked then
continue;
if Item."Unit Price" = 0 then
continue;
UpdateItemPrice(Item);
end;
for i := 1 to 100 do begin
if i mod 2 = 0 then
continue;
// Only odd numbers reach this line.
ProcessOddNumber(i);
end;
Gotchas and Recommended Approach
- Nested loops:
continueskips only the innermost loop. If you need to skip an outer loop’s iteration, you’ll need a flag variable or to refactor the inner loop into its own procedure. - Don’t forget
Next(): In arepeat ... until Rec.Next() = 0block, theuntilclause still runs aftercontinue, so the cursor advances normally. Just don’t accidentally write a loop that depends on a manualNext()call inside the body before thecontinue—thecontinuewill skip past it. - Use it for guard clauses, not control flow gymnastics:
continueshines when you’re filtering or short-circuiting at the top of the loop. If you’re using it deep in the middle of complex branching, the loop body is probably trying to do too much—consider extracting it into a procedure instead. - Runtime version: Confirm your
app.jsonruntime target supportscontinuebefore using it in a project that needs to deploy to older environments.
Wrapping Up
continue is a small language feature, but it pays off every time you write a loop that has to skip some rows. The “guard clause” style—list the skip conditions at the top, then write the real work at one level of indentation—reads better, reviews better, and tends to be easier to extend.
If you’ve been waiting for AL to catch up to the loop patterns you use in other languages, this is one of those nice ones to finally have.
Learn more:
Note: The code and information discussed in this article are for informational and demonstration purposes only. Always test in a sandbox first. The continue statement is available starting with the AL runtime version introduced in the Microsoft Dynamics 365 Business Central 2025 release wave 1.
