To loop backwards in VBA, start at the highest value, end at the lowest, and use a negative step: For i = 10 To 1 Step -1. The same pattern works for counting down, walking through array elements in reverse, and—especially usefully—deleting worksheet rows without skipping the rows that move up.
The Basic VBA Syntax
A VBA For...Next loop normally advances its counter by one. Add Step -1 to make the counter decrease instead. The first number is the starting value, the number after To is the limit, and the step determines the direction and size of each change.
Sub CountDown()
Dim i As Long
' Print the numbers from 10 down to 1.
For i = 10 To 1 Step -1
Debug.Print i
Next i
End Sub
This prints 10, 9, 8, and so on through 1 in the Visual Basic Editor’s Immediate window. The loop variable must be numeric. Long is generally a sensible choice for row numbers and counters; an Integer can hold only values from -32,768 to 32,767, which is too small for many Excel row positions.
The Step value is the amount added to the counter after each pass. A negative value counts down: Step -2 visits every other number. The step cannot be zero. If the starting value is already below the ending value while using a negative step, the loop does not run. That directional mismatch is a common reason a backward loop appears to do nothing.
How the Loop Counts
VBA checks the loop’s starting value, limit, and step, then repeats the statements while the counter has not passed the limit in the direction of travel. With a negative step, the counter moves toward smaller values. For example, a loop from 5 to 1 with Step -1 visits 5, 4, 3, 2, and 1.
The limit is not necessarily a value the loop will visit. The counter advances by the step size, and the loop stops when it has passed the limit. For instance, counting from 10 to 2 by -3 visits 10, 7, and 4; the next value would be 1, which has passed 2. Choose a step that matches the sequence you need rather than assuming VBA will adjust the last value to land exactly on the limit.
Use For...Next when the starting and ending bounds are known or can be calculated before the loop. If the number of passes depends on a condition that may change during processing, a Do While or Do Until loop may be more suitable. For straightforward reverse counting, however, a negative-step For loop makes the direction clear.
Looping Backward Through Worksheet Rows
Reverse iteration is particularly important when a macro deletes rows. Suppose a macro checks rows from the top down and deletes row 5. The old row 6 moves into row 5, but the loop counter advances to row 6. The moved row is therefore never checked. Deleting from the bottom upward avoids that shift problem: rows above a deletion keep their row numbers.
In this example, the data starts on row 2, row 1 contains headings, column A has a value on every data row, and column C contains the instruction “Remove” for rows to delete. Change the worksheet name and columns to match your workbook. Save a copy of the workbook before running a macro; VBA changes cannot be undone with Ctrl+Z.
Sub DeleteMarkedRows()
Dim ws As Worksheet
Dim lastRow As Long
Dim r As Long
' The worksheet and columns here are example assumptions.
Set ws = ThisWorkbook.Worksheets("Data")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
' Keep the heading row and exit if there are no data rows.
If lastRow < 2 Then Exit Sub
' Check from the bottom upward so deletions do not skip rows.
For r = lastRow To 2 Step -1
If ws.Cells(r, "C").Value = "Remove" Then
ws.Rows(r).Delete
End If
Next r
End Sub
The macro finds the last populated cell in column A by moving upward from the bottom of the worksheet. That is reliable only if column A is populated for every row that should be considered. If another column is a better marker, use that column in the Cells reference. If rows can contain data below the last value in the chosen marker column, this method will not include them.
The loop starts at the last row and stops at row 2, so it does not inspect or delete the heading row. If your data begins on a different row, update both the starting boundary and the lower limit. A check such as If lastRow < 2 Then Exit Sub also prevents the macro from treating a heading-only sheet as if it had data to process.
Arrays and Collections in Reverse Order
Arrays can also be traversed from their upper bound to their lower bound. Do not assume every VBA array starts at index zero or one: its actual bounds depend on how it was declared or created. Use UBound for the highest valid index and LBound for the lowest.
Sub PrintArrayBackwards()
Dim values As Variant
Dim i As Long
' Array creates a zero-based array in this example.
values = Array("red", "green", "blue")
For i = UBound(values) To LBound(values) Step -1
Debug.Print values(i)
Next i
End Sub
This prints blue, green, then red. Using the bounds rather than hard-coding 2 and 0 makes the loop adaptable if the array’s size changes. A dynamic array that has not been allocated does not have usable bounds, so check that it has been initialized before calling LBound or UBound.
VBA collections are indexed from 1, not 0. If you need to remove entries while iterating through a Collection, work from items.Count down to 1. Removing an item shifts later entries to lower indexes; moving backward ensures the shift does not cause an item that still needs checking to be skipped. A forward indexed loop can also run into an invalid index if the collection becomes shorter during the loop.
That guidance applies to indexed removal, not every kind of collection traversal. A For Each loop is convenient when you only need to read each item, but changing a collection while enumerating it can be unsafe or unsupported. When modifying membership, use a carefully bounded indexed loop or collect the items to remove and delete them in a separate pass.
Choosing the Right Bounds and Loop Type
Before writing a backward loop, identify what the numbers represent. In a worksheet loop, they are usually row numbers; in an array loop, they are indexes; in a countdown, they are simply values. Make the top and bottom boundaries explicit so the code does not accidentally include a header, examine a nonexistent index, or stop one position too early.
- Use a descending
Forloop when both bounds are known and you want a predictable sequence. - Use
UBoundandLBoundwhen traversing an array whose size or lower bound may vary. - Count backward when deleting or removing indexed items so earlier positions are not disrupted by items shifting.
- Use a conditional loop when the stopping point is determined by a condition rather than a fixed boundary.
For worksheet loops, decide how to find the last row as carefully as how to count backward. Cells(Rows.Count, "A").End(xlUp).Row is a common approach when column A is consistently filled. If records have gaps in that column, the result may not represent the last row containing any data. Pick a dependable key column or use a more deliberate method suited to the sheet’s structure.
Common Errors and Troubleshooting
The most frequent mistake is leaving out the negative step. For i = 10 To 1 uses the default positive step of 1; since 10 is already above 1, that loop does not count down. Write Step -1 explicitly so the direction is both correct and easy to read.
Another error is mixing up the endpoints. When deleting rows while keeping a header, the upper endpoint is usually the last data row and the lower endpoint is the first data row—not row 1. When traversing an array, use its actual bounds instead of assuming that the last index equals the number of elements. An array with indexes 1 through 5 has five elements, but its highest index is 5; an array with indexes 0 through 4 also has five elements.
Also avoid changing the loop counter inside the loop unless there is a specific reason. A statement that manually changes r can interact with the automatic step performed by Next r, making the sequence hard to reason about. If the loop should skip positions, express that in the Step value where possible.
When a loop runs but appears to produce no output, check its bounds and direction first. Then confirm that the code inside the loop reaches the expected branch. For the countdown example, open the Visual Basic Editor’s Immediate window to see Debug.Print output. In the editor, use View > Immediate Window. A macro can also be single-stepped in the Visual Basic Editor to inspect the counter and current row as execution proceeds.
Running VBA in Excel for Microsoft 365
On Windows desktop Excel, open the Visual Basic Editor with Alt+F11, or choose Developer > Visual Basic if the Developer tab is visible. On Mac, Option+F11 is the usual Visual Basic Editor shortcut; depending on the keyboard’s function-key settings, you may need Fn+Option+F11. The ribbon and editor arrangement can differ on Mac, but the VBA loop syntax is the same.
Put a procedure in a standard module for a typical manually run macro. Save a workbook containing VBA as an Excel Macro-Enabled Workbook (.xlsm) so the code is retained. Excel for the web does not run VBA macros; use the desktop application to run this code. Follow your organization’s macro security rules and only enable macros in workbooks whose source you trust. As noted above, save a separate copy before running a macro that deletes or changes data, because Ctrl+Z does not reverse VBA changes.
Frequently Asked Questions
How do I make a VBA For loop count down?
Set the starting number above the ending number and add a negative step, such as For i = 10 To 1 Step -1. The loop variable should be numeric.
Why does my VBA loop not run backwards?
Check that the code includes Step -1 (or another negative step). Also confirm that the starting value is greater than or equal to the ending value for a descending loop.
Should I loop backwards when deleting Excel rows?
Usually, yes. Deleting from the bottom upward prevents rows moving into an already-checked position and being skipped. Start and stop at the actual data boundaries so headers remain untouched.
How do I loop backwards through an array with unknown bounds?
Use For i = UBound(values) To LBound(values) Step -1 after confirming the array has been initialized. This works with arrays whose lower bound is not zero.
Can I use VBA loops in Excel for the web?
Excel for the web does not run VBA macros. Open the workbook in desktop Excel for Windows or Mac to use VBA.
Related
- Excel Table Row Number: Get the Position or Sheet Row
- Excel Table: Print Headers on Every Page
- Google Sheets Data Cleaning: Tools, Steps, and Tips
Try it: the Column Letter to Number: aA is 27, XFD is 16,384. Converts both ways.
More in VBA & macros
- VBA Outlook Create Contact Group from ExcelYes. In classic Outlook for Windows, an Excel VBA macro can read email addresses from a worksheet, create…
- Outlook Macros: How to Enable Them Safely in Classic OutlookTo enable VBA macros in classic Outlook for Windows, open File > Options > Trust Center > Trust…
- Excel VBA Delete Row: Methods, Examples, and Best PracticesTo delete a worksheet row with Excel VBA, reference the worksheet and call its Rows collection’s Delete method—for…
- Read a Text File with Excel VBA: Methods and ExamplesYes. In Excel for Microsoft 365 on Windows, VBA can read a plain-text file with the Open and…
- VBA Loop Through Excel Tables by Name in a WorkbookIn Excel VBA, access a table by its name through the worksheet’s ListObjects collection: use ThisWorkbook.Worksheets("Data").ListObjects("SalesTable"). To loop…
- VBA Loop Code: Examples for Excel MacrosVBA loop code repeats an instruction for a set number of times, for each item in a collection,…
Sources: Function behaviour and menu paths: Microsoft Support documentation for Excel. Method & sources
Spotted an error in this guide? Let us know.