> ## Content Index
> Fetch the complete content index at: https://nolongerset.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Block-Level Scope in VBA...Does Not Exist
- URL: https://nolongerset.com/block-level-scope/
- Published: 2023-01-12T04:16:30.000Z
- Updated: 2026-05-08T12:52:24.000Z
- Description: VB.NET and VBA may look the same, but there are some important differences. This is a little-known feature of VB.NET that I really wish was available in VBA.
- Author: Mike Wolfe
- Tags: VBA, Intermediate, #Import 2026-05-20 02:59

One of many differences between VBA and VB.NET is that [VB.NET has block-level scope](https://learn.microsoft.com/en-US/dotnet/visual-basic/programming-guide/language-features/declared-elements/scope#block-scope) and [VBA does not](https://nolongerset.com/scope-vs-extent-in-vba/#scope).

A "block" is a set of statements with an opening and closing line of code, such as:

- `If` ... `End If`
- `With` ... `End With`
- `Select Case` ... `End Select`
- `Do` ... `Loop`

With block-level scope, "if you declare a variable within a block, you can use it only within that block." 

## Block-Level Scope Restrictions in VB.NET

If you try to run the code below in VB.NET, you will get a bunch of compile errors as indicated in the comments and shown in the screenshot below the code:

```vba
Sub TestDim()
    Console.WriteLine(a)  '<-- Local variable 'a' cannot be referred to before it is declared.
    Dim a As Long

    If True Then
        Dim b As Long
    End If
    Console.WriteLine("b:" & b)  '<-- 'b' is not declared. It may be inaccessible due to its protection level. 

    If False Then
        Dim c As Long
    End If
    Console.WriteLine("c:" & c)  '<-- 'c' is not declared. It may be inaccessible due to its protection level. 

    With Today
        Dim d As Long
    End With
    Console.WriteLine("d:" & d)  '<-- 'd' is not declared. It may be inaccessible due to its protection level. 

    Select Case a
        Case 0
            Dim e As Long
        Case 1
            Dim f As Long
        Case Else
            Dim g As Long
    End Select
    Console.WriteLine("e:" & e)  '<-- 'e' is not declared. It may be inaccessible due to its protection level. 
    Console.WriteLine("f:" & f)  '<-- 'f' is not declared. It may be inaccessible due to its protection level. 
    Console.WriteLine("g:" & g)  '<-- 'g' is not declared. It may be inaccessible due to its protection level. 

    For a = 1 To 2
        Dim h As Long
    Next
    Console.WriteLine("h:" & h)  '<-- 'h' is not declared. It may be inaccessible due to its protection level. 

    Do Until a > 2
        Dim i As Long
        a = a + 1
    Loop
    Console.WriteLine("i:" & i)  '<-- 'i' is not declared. It may be inaccessible due to its protection level.

End Sub
```

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2023/01/image-10.png)

## No Block-Level Scope Restrictions in VBA

The nearly identical code below *WILL* compile in VBA. 

*(I commented out the first line because that is the only one that will throw a compile error in VBA.)*

```vba
Sub TestDim()
    'Debug.Print a  '<-- Compile error: Variable not defined (if uncommented)
    Dim a As Long
    
    If True Then
        Dim b As Long
    End If
    Debug.Print "b:" & b  'Available even though declared inside If ... End If block
    
    If False Then
        Dim c As Long
    End If
    Debug.Print "c:" & c   'Available even though its declaration can't be reached at runtime
    
    With CurrentProject
        Dim d As Long
    End With
    Debug.Print "d:" & d   'Available even though declared inside With ... End With block
    
    Select Case a
    Case 0
        Dim e As Long
    Case 1
        Dim f As Long
    Case Else
        Dim g As Long
    End Select
    'All three variables are available even though declared inside Select Case block
    Debug.Print "e:" & e
    Debug.Print "f:" & f
    Debug.Print "g:" & g
    
    For a = 1 To 2
        Dim h As Long
    Next
    Debug.Print "h:" & h  'Available even though declared inside For ... Next block
    
    Do Until a > 2
        Dim i As Long
        a = a + 1
    Loop
    Debug.Print "i:" & i  'Available even though declared inside Do Until ... Loop block
    
End Sub
```

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2023/01/image-11.png)

Every `Debug.Print` block in the VBA sample code above works even though their associated variables were declared inside of a code block and are being referenced from outside that code block.

## Only One VBA Rule - Declare Before Use

Assuming you are using `Option Explicit` (and you should [***always*** use Option Explicit](https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/option-explicit-statement)), you only need to remember one rule when it comes to local variables:

> In VBA, you must declare a local variable before you use it.

That's it. The block-level scoping restrictions in VB.NET ***do not apply*** to VBA. In VBA, the most restrictive level of scope is procedure-level scope.

## This is a VBA Shortcoming

Why? Because it eliminates an entire class of potential compile errors. And compile errors are good! Okay, maybe they're not good, *per se*. But they are [much cheaper and easier to fix than logic errors](https://nolongerset.com/some-bugs-are-better-than-others/). 

So, even though the VBA compiler won't *enforce* block-level scope, I still try to write my code as if it did. In other words, **if I only need to use a variable inside of a code block**, then I will:

1. Declare the variable inside the code block
2. Not reference the variable outside the code block

While I would much rather the compiler enforce this restriction, adopting this as a policy still allows me to *convey my intent* for how I expect the variable to be used within the procedure.