🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA GoTo in Excel — Jumping to a Label, and Why You Usually Should Not

|

VBA GoTo in Excel — Jumping to a Label, and Why You Usually Should Not

TL;DR — GoTo label jumps execution to a line marked label: in the same procedure, with no condition attached. It has exactly one place it still belongs in modern VBA: On Error GoTo for error handling. For everything else — loops, skipping, branching — a jump is harder to follow than the structured tools (If, Exit For, Exit Sub, Do), and jumping into or out of a loop quietly corrupts the loop. Learn the syntax so you can read old code; reach for the structured version when you write new code.

Sub GoToBasics()
    Dim x As Long
    x = 5
    If x > 0 Then GoTo Positive

    Debug.Print "zero or negative"
    Exit Sub                 ' stop before falling into the label below

Positive:                    ' a label - name followed by a colon
    Debug.Print "positive"
End Sub

GoTo is the oldest control-flow tool there is: it moves execution to a named label, unconditionally and in one direction of your choosing. VBA still supports it, and one modern feature — On Error GoTo — is built on it. But for ordinary flow, a jump makes code you cannot read top to bottom, and that is why almost every GoTo in new code should be an Exit or an If instead.

What you'll learn

  • The label-and-jump syntax: how you write a label and how GoTo reaches it
  • The one place GoTo genuinely belongs today — On Error GoTo error handling
  • Why jumping into or out of a loop corrupts the loop counter and leaves work half-done
  • How GoTo gets misused to fake a Continue VBA does not have, and the clean alternative
  • Why you cannot GoTo a label in another procedure
  • The structured replacements that read better than any jump

The mental model: an unconditional one-way jump

A label is a name followed by a colon, alone on a line; GoTo label moves execution straight to it:

GoTo CleanUp     ' jump forward (or backward) to the line marked CleanUp:
' ... any lines here are skipped ...
CleanUp:         ' <-- execution resumes here

Two properties make GoTo powerful and dangerous in equal measure. It is unconditional — on its own it always jumps, so branching requires wrapping it in an If — and it is a one-way move that leaves no trail: nothing marks where control came from, so a reader tracing the code has to scan the whole procedure to find every GoTo that could land on a label. A structured statement like Exit For tells you exactly where control goes (just past Next); a GoTo can come from anywhere. That difference is the entire case against it.

The one place GoTo belongs: On Error GoTo

Here is the exception, and it is a real one. VBA's error handling is built on GoTo: On Error GoTo tells VBA which label to jump to when a run-time error occurs. This is idiomatic, expected, and has no structured alternative in the language:

Sub SafeOpen()
    On Error GoTo Failed
    Workbooks.Open "C:\reports\data.xlsx"
    Exit Sub

Failed:
    MsgBox "Could not open the file."
End Sub

Notice the Exit Sub before the Failed: label — without it, the normal path would fall through into the error handler even when nothing went wrong. That fall-through is the classic GoTo-labelled-code bug, and it applies to every label, not just error handlers. For the full mechanism, see VBA On Error. Outside of On Error, a GoTo is a warning sign, not a tool.

The trap: jumping into or out of a loop

The worst thing you can do with GoTo is jump across the boundary of a For or Do loop. Jump out of a loop with GoTo and you bypass the loop's normal exit — the counter is left at whatever value it held, and anything the loop was meant to finish is skipped. Jump into the middle of a loop and the result is worse: the counter was never initialised, so behaviour is undefined:

' DO NOT do this - jumping out of a loop with GoTo
For i = 1 To 100
    If Cells(i, 1).Value = "X" Then GoTo AfterLoop   ' skips the loop's clean exit
Next i
AfterLoop:

The line above happens to run, but the honest version is Exit For, which leaves the loop through its proper door and makes the intent obvious. Every "jump out of a loop" is better written as Exit For or Exit Do; every "leave the procedure now" is better written as Exit Sub. Those name the structure they leave and land control somewhere predictable — a GoTo does neither.

Faking Continue with GoTo — and the clean alternative

VBA has no Continue statement to skip to the next loop iteration, so old code often simulates it by placing a label just before Next and jumping to it:

' the GoTo way to "continue" - works, but it is a jump
For i = 1 To n
    If Cells(i, 1).Value = "" Then GoTo NextRow
    ' ... process the row ...
NextRow:
Next i

This runs, but it asks the reader to jump around to understand a loop. The structured version simply inverts the test so the skipped iterations do nothing and fall through to Next:

' the structured way - no label, no jump
For i = 1 To n
    If Cells(i, 1).Value <> "" Then
        ' ... process the row ...
    End If
Next i

Same behaviour, read straight down. When the skip condition is a single test, the If always wins. Save the label-before-Next pattern for the rare case where the skip logic is too involved for one If — and even then, consider splitting the body into its own procedure.

You cannot GoTo across procedures

A label is local to the procedure it lives in. GoTo can only jump to a label in the same Sub or Function; you cannot jump from one procedure into another. VBA raises the compile error Label not defined. If you find yourself wanting to jump into another procedure, what you actually want is to call it — MyCleanup or Call MyCleanup — which returns control to you afterward, exactly what a jump cannot do. This limitation is a feature: it keeps every jump inside one readable unit.

When a jump is genuinely the least-bad option

Honesty demands one concession: breaking out of deeply nested loops is the one control-flow situation where a GoTo to a label past the outer loop can be cleaner than the alternatives, because VBA cannot Exit more than one loop level at a time. Even here, extracting the nested loops into a Function and using Exit Function is usually clearer. The rule of thumb: if you are reaching for GoTo and it is not On Error GoTo, stop and ask whether an Exit, an If, or a small helper procedure would say the same thing without a jump. Ninety-nine times out of a hundred, it will.

How ExcelMaster helps

GoTo is easy to write and hard to read, which is exactly the combination that produces macros nobody can maintain six months later. The two mistakes that bite are the fall-through into a label when a preceding Exit Sub is missing, and jumps across loop boundaries that leave counters and work in an undefined state.

ExcelMaster writes flow you can read top to bottom: Exit For where a loop should stop, guard clauses where a procedure should bail out, and On Error GoTo only where it belongs — in error handling, with the Exit Sub that keeps the normal path out of the handler. You keep the workbook and the code.

Frequently asked questions

What does GoTo do in VBA?

GoTo label transfers execution unconditionally to a line marked label: in the same procedure. A label is a name followed by a colon on its own line. Because GoTo always jumps, branching requires wrapping it in an If, as in If x < 0 Then GoTo Negative. Execution then continues from the label onward.

Is GoTo bad practice in VBA?

For ordinary control flow, yes — a jump is harder to follow than structured statements, and jumping into or out of a loop can corrupt the loop counter. The important exception is On Error GoTo, which is the idiomatic and expected way to route run-time errors to a handler. Learn GoTo to read old code; prefer Exit, If, and Do loops when you write new code.

How do I write a label for GoTo?

Put a name followed by a colon on its own line, such as CleanUp:, and jump to it with GoTo CleanUp. Labels are case-insensitive and local to the procedure. Always place an Exit Sub before a label that sits at the end of a procedure, or the normal path will fall through into the labelled code even when no jump was intended.

Can GoTo jump to another Sub or Function?

No. A GoTo can only reach a label in the same procedure; jumping into another Sub or Function is a compile error. To run code in another procedure, call it by name — the call returns control to you when it finishes, which is what you usually want and what a jump can never do.

How do I break out of a loop without GoTo?

Use Exit For for a For loop or Exit Do for a Do loop — both leave the loop through its proper exit and continue at the line after it. To skip a single iteration rather than leave the loop, wrap the body in an If so the skipped passes do nothing. See VBA Exit For for the full set.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-09-24.

Related guides: VBA Exit For · VBA End · VBA On Error · VBA For Loop · VBA If Then Else