Skip to content
JavaScript js control-flow 4 min read

break, continue & Labels

Loops run until their condition fails, but real-world logic rarely fits that neat shape. Sometimes you want to stop early the moment you find what you need, and sometimes you want to skip one awkward iteration and keep going. The break and continue statements give you that fine-grained control, and labels let them reach beyond the innermost loop. Used well, they make algorithms shorter and clearer; used carelessly, they hide bugs.

Breaking out of a loop

break immediately terminates the nearest enclosing loop (for, for...of, for...in, while, or do...while) and resumes execution at the statement after it. It is the classic “I found it, stop searching” tool.

const numbers = [4, 8, 15, 16, 23, 42];
let firstEven = null;

for (const n of numbers) {
  if (n % 2 === 0) {
    firstEven = n;
    break; // stop as soon as we have an answer
  }
}

console.log(firstEven);

Output:

4

Without break, the loop would keep scanning every remaining element for no reason. For very large collections that wasted work adds up, so breaking early is both clearer and faster.

Note: break also exits a switch statement. Inside a loop that contains a switch, a break belongs to the switch, not the loop — reach for a label if you need to break the loop from inside the switch.

Skipping with continue

continue does not leave the loop; it jumps straight to the next iteration, skipping the rest of the current loop body. It is ideal for filtering out cases you don’t care about without nesting your real logic inside an if.

const orders = [
  { id: 1, status: "paid" },
  { id: 2, status: "pending" },
  { id: 3, status: "paid" },
];

for (const order of orders) {
  if (order.status !== "paid") continue; // ignore unpaid orders
  console.log(`Shipping order #${order.id}`);
}

Output:

Shipping order #1
Shipping order #3

In a for loop, continue still runs the update expression (the i++ part), so you won’t accidentally create an infinite loop. In a while loop, however, make sure any counter is incremented before the continue, or the condition may never change.

Labeled statements

By default break and continue only affect the innermost loop. A label — an identifier followed by a colon placed before a loop — lets you target an outer loop explicitly. This is the cleanest way to escape nested loops in one step.

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

outer: for (let row = 0; row < grid.length; row++) {
  for (let col = 0; col < grid[row].length; col++) {
    if (grid[row][col] === 5) {
      console.log(`Found 5 at [${row}][${col}]`);
      break outer; // exit BOTH loops at once
    }
  }
}

Output:

Found 5 at [1][1]

continue label works the same way but resumes the next iteration of the labeled loop instead of ending it:

rows: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (j === i) continue rows; // skip to the next row early
    console.log(`i=${i}, j=${j}`);
  }
}

Output:

i=1, j=0
i=2, j=0
i=2, j=1
StatementAffectsEffect
breaknearest loop / switchExits the construct entirely
continuenearest loopSkips to the next iteration
break labelthe labeled loopExits the labeled (often outer) loop
continue labelthe labeled loopSkips to the labeled loop’s next iteration

Readable alternatives

Labels are powerful but easy to abuse, and deeply labeled jumps can be hard to follow. Often you can express the same intent more readably.

Extracting the loop into a function lets a plain return exit every level at once — no labels required:

function findValue(grid, target) {
  for (const row of grid) {
    for (const cell of row) {
      if (cell === target) return cell; // unwinds all loops
    }
  }
  return null;
}

console.log(findValue([[1, 2], [3, 4]], 4));

Output:

4

For array searches, built-in methods often remove the need for manual break entirely. find, some, and findIndex all short-circuit on the first match:

const numbers = [4, 8, 15, 16, 23, 42];

const firstEven = numbers.find((n) => n % 2 === 0);
const hasBig = numbers.some((n) => n > 40);

console.log(firstEven, hasBig);

Output:

4 true

Tip: You cannot break or continue out of an Array.prototype.forEach callback — it ignores both. If you need early exit, use a for...of loop or switch to find/some/every.

Best Practices

  • Use break to stop as soon as the answer is known; avoid pointless extra iterations.
  • Prefer continue over wrapping the whole loop body in an if to filter unwanted cases — it flattens nesting.
  • Reach for labels only for genuine nested-loop control flow, and give them descriptive names like outer or rows.
  • When a labeled break/continue makes code hard to read, extract the loops into a function and use return instead.
  • For array lookups, prefer find, some, every, or findIndex, which short-circuit and express intent clearly.
  • Remember that break inside a switch targets the switch, not the surrounding loop.
  • Never rely on break/continue inside forEach — they have no effect there.
Last updated June 1, 2026
Was this helpful?