JavaScript Break Continue

break and continue are jump statements that change the normal, top-to-bottom flow of a loop. break exits a loop (or a switch) immediately, while continue skips the rest of the current iteration and jumps straight to the next one. Together they let you write loops that stop early when you’ve found what you need, or skip over values you don’t care about, instead of relying on complicated nested conditionals.

Overview: How Loops and Jump Statements Work

A loop (for, while, do...while, for...of, for...in) normally runs its body once per iteration until its condition becomes false. Internally, the JavaScript engine tracks a loop as a single control structure with three parts it manages automatically: the test condition, the body, and (for for loops) the update expression. On every pass, it evaluates the condition, and if true, executes the body from top to bottom, then loops back around.

break and continue hook directly into that control structure:

  • break tells the engine “stop managing this loop entirely — jump to the first line of code after the loop’s closing brace.” No further conditions are checked and no further iterations happen.
  • continue tells the engine “stop executing the body for this iteration, but don’t abandon the loop — go straight to the update step (for for loops) or the condition check (for while loops) and keep going.”

Both statements only make sense inside an enclosing loop (or, for break, inside a switch statement too). If you write break or continue outside any loop or switch, or inside a nested function that isn’t itself a loop, JavaScript throws a SyntaxError at parse time — before your code even runs. This is a compile-time check, not a runtime one, which is why it’s called an “illegal” statement rather than a thrown exception.

Syntax

break;
break label;

continue;
continue label;

label: for (...) {
  // loop body
}
Form Meaning
break; Exits the nearest enclosing loop or switch immediately.
continue; Skips to the next iteration of the nearest enclosing loop.
label: An identifier placed before a loop, letting break/continue target that specific loop instead of the innermost one.
break label; Exits the labeled loop entirely, even from inside a nested loop.
continue label; Skips to the next iteration of the labeled (outer) loop, not the innermost one.

A label is just an identifier followed by a colon, placed directly before the loop keyword. It is not a string, and it lives in its own namespace — it won’t collide with variable names.

Examples

Example 1: Using break to stop searching early

const numbers = [4, 9, 15, 23, 30, 42];
let firstOver20;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] > 20) {
    firstOver20 = numbers[i];
    break;
  }
}

console.log(`First number over 20: ${firstOver20}`);
console.log(`Loop stopped early, did not check all ${numbers.length} numbers`);

Output:

First number over 20: 23
Loop stopped early, did not check all 6 numbers

As soon as numbers[i] > 20 becomes true at index 2 (value 23), break exits the loop immediately. The engine never looks at 30 or 42, even though they also satisfy the condition — this is exactly what makes break efficient for “find the first match” logic.

Example 2: Using continue to skip values

for (let i = 1; i <= 10; i++) {
  if (i % 3 === 0) {
    continue;
  }
  console.log(i);
}

Output:

1
2
4
5
7
8
10

Every time i is a multiple of 3, continue skips the console.log(i) line for that iteration only — the loop doesn’t stop, it just moves on to increment i and check the condition again. Notice that 3, 6, and 9 are missing from the output, but the loop still counts all the way up to 10.

Example 3: Labeled break in nested loops

const matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

let found = null;

outer: for (let row = 0; row < matrix.length; row++) {
  for (let col = 0; col < matrix[row].length; col++) {
    if (matrix[row][col] === 5) {
      found = { row, col };
      break outer;
    }
  }
}

console.log(found);

Output:

{ row: 1, col: 1 }

A plain break inside the inner loop would only exit the inner loop, leaving the outer row loop to keep running unnecessarily. By labeling the outer loop outer: and writing break outer;, both loops stop the moment the value 5 is found, avoiding wasted iterations over the rest of the matrix.

Under the Hood: Step by Step

Walking through Example 3 helps show exactly what the engine does:

  • The engine enters the outer loop, sets row = 0, and enters the inner loop with col = 0.
  • For each col, it checks matrix[row][col] === 5. On row 0, none of the values match, so the inner loop finishes normally and the outer loop advances to row = 1.
  • On row 1, col = 1 gives matrix[1][1] === 5, which is true. The engine assigns found and executes break outer;.
  • Because the label targets the outer loop, the engine discards both the remaining inner-loop iterations and the remaining outer-loop iterations, jumping straight to the line after the outer loop’s closing brace.

This is fundamentally different from a plain break in that spot: without the label, only the inner loop would stop, and the outer loop would proceed to row = 2, checking row 2 pointlessly.

Common Mistakes

Mistake 1: Using break or continue inside a callback like forEach

A very common mistake is trying to break out of an Array.prototype.forEach call:

const numbers = [1, 2, 3, 4, 5];

numbers.forEach((num) => {
  if (num === 3) {
    break;
  }
  console.log(num);
});

This throws SyntaxError: Illegal break statement and won’t even parse. The callback passed to forEach is its own function — break can only target a loop or switch in the same function scope, and there is no loop inside that arrow function for it to break out of. forEach itself has no built-in way to stop early.

The fix is to use an actual loop construct that supports break, such as for...of:

const numbers = [1, 2, 3, 4, 5];

for (const num of numbers) {
  if (num === 3) {
    break;
  }
  console.log(num);
}

Output:

1
2

If you specifically need to find something rather than just stop iterating, array methods like .find(), .some(), or .every() are often an even cleaner alternative, since they’re designed to short-circuit internally.

Mistake 2: continue skipping the update step and causing an infinite loop

In a while loop, the increment isn’t automatic the way it is in a for loop — you have to write it yourself. If continue appears before the line that updates the loop variable, it skips that update every time the condition is met, and the loop condition never changes. For example, writing if (i === 2) { continue; } followed later by i++; means that once i reaches 2, continue always fires before i++ runs, so i is stuck at 2 forever — the loop never terminates.

The fix is to make sure any variable the loop condition depends on is updated before the continue check, not after it:

let i = 0;
while (i < 5) {
  i++;
  if (i === 3) {
    continue;
  }
  console.log(i);
}

Output:

1
2
4
5

Because i++ now runs first, every path through the loop body updates i, so the loop is guaranteed to eventually reach its exit condition regardless of when continue fires.

Best Practices

  • Reach for break when you’re searching and want to stop as soon as a condition is satisfied — it avoids scanning the rest of a collection needlessly.
  • Use continue to handle “skip this one” cases at the top of a loop body, which keeps the rest of the body free of an extra layer of if nesting.
  • Prefer array methods (.find(), .some(), .every(), .filter()) over manual loops with break/continue when you’re just testing or searching a collection — they read more declaratively.
  • Use labeled break/continue sparingly, only for nested loops where a plain break would be ambiguous or insufficient; overusing labels can make control flow harder to follow.
  • Never use break or continue inside a callback function (like the one passed to forEach, map, or setTimeout) — they only work in the function scope where the loop itself is written.
  • In while and do...while loops, always double-check that every branch, including ones with continue, still updates whatever variable controls the loop’s exit condition.

Practice Exercises

  • Exercise 1: Write a for loop over the numbers 1 through 20 that logs each number, but stops completely (using break) as soon as it reaches a number greater than 12.
  • Exercise 2: Given an array of words, use continue inside a for...of loop to log only the words with more than 4 letters, skipping shorter ones.
  • Exercise 3: Write two nested loops representing a 4×4 grid of numbers 1-16. Use a labeled break to stop both loops as soon as you find the number 10, and log the row and column where it was found.

Summary

  • break exits the nearest enclosing loop (or switch) immediately, skipping any remaining iterations.
  • continue skips only the rest of the current iteration and moves on to the next one — the loop keeps running.
  • Both statements are checked at parse time: using them outside a loop or switch, or inside a nested callback function, causes a SyntaxError before the code runs.
  • Labels (label: for (...) {...}) let break label; and continue label; target an outer loop from inside a nested one.
  • In while/do...while loops, make sure the loop’s update logic runs before any continue check to avoid accidental infinite loops.
  • For simple searches, array methods like .find() or .some() are often clearer than manual loops with break.