Last Updated: May 22, 2026
break and continue are the two ways Go lets you change a loop's normal flow. break stops a loop early. continue skips the rest of the current iteration and jumps to the next one. They look simple, and most of the time they are, but a few sharp edges around switches, selects, and nested loops are worth knowing.
break Doesbreak exits the innermost enclosing for, switch, or select statement. Control jumps to the first line after that statement, and the loop (or switch, or select) is done. The classic use is "I'm searching for something, and I want to stop the moment I find it." A cart lookup is a good example:
Once break runs, the loop is done. The remaining cart items are never examined. Use break to stop work the moment you have your answer. The found flag lets the caller print "Not in cart" if the match never happened.
Cost: Without break, the loop walks the entire slice even after finding the match. For a five-item cart that's nothing, but at scale it's the difference between O(k) (stop at first match) and O(n) (always scan everything).
continue Doescontinue skips the rest of the current iteration and jumps to the next one. The loop variable advances, the condition is re-checked, and the body runs again from the top. The classic use is "I want to skip some items but keep processing the rest." An out-of-stock filter is a good fit:
The two out-of-stock products are skipped, but the loop keeps running and processes everything else. If you'd used break here instead of continue, the loop would have stopped at "Headphones" and you'd never have seen "Mouse" or "Monitor".
break exits the loop, continue exits the iteration. One stops everything; the other stops the current pass.
The two keywords look similar, but they take very different paths through a loop:
continue is a shortcut to the next iteration's check; the loop carries on. break is a shortcut to the exit; the loop is done. Both bypass the rest of the body, in different directions.
break Inside switchA switch statement in Go doesn't fall through to the next case by default. Each case ends automatically when its block finishes, so you never need a closing break to prevent fall-through. The code below is already correct without one:
No break anywhere, and only the matching case runs. That's the default behavior.
The reason break is still allowed inside a switch is to let you exit the switch early, before its case block finishes naturally. That's rare, but it shows up when a case does some work, hits a condition, and decides there's no point in continuing:
The break short-circuits the rest of the case "shipped" block once the empty-order condition fires. The other cases don't run either, because cases never fall through.
There's an important wrinkle when switch is inside a for. A bare break in a switch case exits the switch, not the surrounding loop. This is the most common confusion:
The "stopping" message prints, but the loop calmly moves on to "delivered". break exits only the innermost enclosing for, switch, or select, and the switch was innermost. Breaking out of the outer for from inside the switch needs a labeled break.
break Inside selectselect is the channel equivalent of switch: it picks one of several channel operations that's ready and runs that case. break works the same way it does in a switch, it exits the select, not any surrounding loop.
A common pattern is a worker loop with a select for timeout handling.
When the channel closes, break exits the select, but the for is still running and the next select runs again. Eventually the timeout case fires and return exits the function. The takeaway here: break inside select exits the select, just like inside a switch.
Three patterns make up most real-world uses of break and continue.
When you're looking for a specific item, stop the moment you find it:
The loop stops at index 2. Indexes 3 onwards are never examined. For a small catalog this saves nothing, but the pattern scales: you're paying for "find" cost, not "scan everything" cost.
When you want to process most items but skip the bad ones:
Each continue peels off one bad item without bringing the whole loop down. Stacking validations as a series of continues keeps the happy-path math (the subtotal += line) un-indented, which is easier to read than nesting it inside if item.Quantity > 0 { if item.Price >= 0 { ... } }.
When you're scanning input and a single bad value means the whole operation is invalid, break lets you bail out:
The fourth and fifth prices are never looked at. That's deliberate: the data is corrupted, and continuing to add prices would produce a number that looks fine but isn't trustworthy.
Both break and continue target the innermost enclosing statement. For continue, that's always the innermost for. For break, it's the innermost for, switch, or select. This is where nested loops get tricky.
Consider a grid of category-by-product stock counts. You want to find the first product anywhere in the grid that has stock:
That's almost certainly not what was intended. The break exited the inner loop on the first match in each row, but the outer loop kept going and ran the inner loop again on the next row. So instead of one match, you got one per row that had any stock.
This is a common break mistake: expecting it to exit both loops, when it only exits the innermost. The cleanest fix is usually to extract the loops into a function and return on the match:
return exits both loops and the function in one step. The other two options are a flag variable checked after the inner loop (works, but the bookkeeping is annoying) and a labeled break, which targets an outer loop by name.
break and continue are useful, but overusing them can produce code that's hard to read. Two alternatives often work better.
A guard clause is an early-out check at the top of a function or block. It says "if the input is bad, bail now" and lets the rest of the code assume good input. Compare a heavily indented version with a flat one:
The two return statements at the top short-circuit the bad-input cases so the rest of the function doesn't have to be wrapped in nested if blocks. Inside the loop, continue plays the same role for items: skip the empty one, keep the happy path at the leftmost indentation.
If your loop is "find something and use it," consider whether the loop belongs in its own function. Extracting the loop (as findFirstInStock did earlier) lets you return instead of juggling a break and a flag. The rule of thumb: if a break or continue forces extra flags, deep nesting, or hard-to-trace control flow, refactor. If it's genuinely the simplest thing, use it.
Three traps catch people regularly.
break to Exit Both LoopsCovered in the nested-loop section. A bare break exits only the innermost loop. To exit the outer loop too, use a flag, a labeled break, or extract a function with return.
break in a Switch With Breaking the Outer LoopWhen a switch is inside a for, break inside a case exits the switch, not the loop:
The "stop the loop" comment is wishful thinking. To actually stop the loop, you'd set a flag, use a labeled break, or return from a surrounding function.
continueIn a three-clause for, the post-statement always runs on continue. But if you manage the counter yourself inside the body, continue will skip that line and you'll loop forever:
continue jumps back to the condition check, but i is still the same value, so the loop hangs. The fix is to use the three-clause for (where i++ is the post-statement and always runs) or range (where the iteration variable advances automatically):
A small example combining all three patterns: skip cancelled orders with continue, abort on a corrupted record with break, and look up a target order along the way.
Order 1001 adds 49.99, 1002 is skipped, 1003 is recorded as the target match and adds 199.00, and 1004 triggers break. Order 1005 is never examined. A loop doing three jobs at once is on the edge of readability; in real code, three smaller loops are usually cleaner.