TL;DR —
Debug.Print exprwrites one line to the Immediate Window and lets the macro keep running. No popup, no pause — the exact opposite ofMsgBox. That makes it the right way to watch a loop stream its values. The catch: the Immediate Window is closed by default, so the number one complaint — Debug.Print does nothing — is almost always output you cannot see. Press Ctrl+G to open it. When you need the log to survive the session, stop printing to the window and write to a file instead.
Sub DebugPrintBasics()
Dim i As Long
For i = 1 To 3
Debug.Print "row " & i, Cells(i, 1).Value ' streams to the Immediate Window
Next i
Debug.Print "done" ' no popup, the macro never pauses
End Sub
' See nothing? The Immediate Window is closed. Press Ctrl+G.
What you'll learn
- The mental model — Debug.Print is a silent, non-blocking log, not a dialog
- The three observers of rising power, and which question each one answers
- Why Debug.Print appears to do nothing (and the Ctrl+G fix)
- Why the Immediate Window quietly drops your earliest output
- Why printing an expression can trigger real side effects
- Debug.Print vs MsgBox, and when the log should become a real file
The mental model: a silent log, not a dialog
Debug.Print is a log line. It appends text to the Immediate Window and immediately returns control
to your code — the macro does not stop, nothing pops up, and no one has to click anything. That single
property is the whole reason it exists. When you are diagnosing a loop, you want to see 5,000 values fly
past in a scrollable panel, not click "OK" 5,000 times.
So the right question in your head is never "how do I show this value?" — MsgBox shows a value. It is
"how do I record a value without interrupting the run?" Everything below follows from that one
framing: because Debug.Print never blocks, its output has to live somewhere you go and look, and that
somewhere is a window Excel keeps hidden until you ask for it.
The three observers, of rising power
Debug.Print is the first rung of a ladder. When a macro misbehaves, you are not short of clues — you are just not looking. VBA hands you three ways to look, each answering a different question and each lying to you in its own way:
| Observer | The question it answers | Its signature lie |
|---|---|---|
Debug.Print |
What were the values as it ran? | Prints to a window that is closed by default |
| Immediate Window | What is true right now, at this pause? | A ? query actually runs the code |
| Breakpoint + F8 | Which line does it go wrong on? | They vanish when you close the workbook |
Reach for the passive one and you are guessing which line broke; reach for the heavy one and you are
stepping through 10,000 iterations by hand. The skill is knowing whether you need to see the values
or find the line. Debug.Print answers the loosest question — it shows you what happened after the
fact — which makes it the fastest to reach for and the easiest to stare straight through.
Trap 1: it prints to a window that is closed by default
The number one "Debug.Print not working" report is not a bug in your code. The values are printing exactly as written — into a panel you have never opened.
Sub WhereDidItGo()
Debug.Print "I am running fine" ' this line works
End Sub ' you just cannot see where it landed
The Immediate Window opens with Ctrl+G (or View > Immediate Window) inside the VBA editor. Until
then, every Debug.Print succeeds silently and you conclude nothing happened. Before you add a single
MsgBox to "check if the code runs," open the Immediate Window — nine times out of ten your evidence was
already there.
Trap 2: the window silently drops your earliest output
The Immediate Window is not an infinite log. It keeps only the last ~200 lines; older lines scroll off the top and are gone. In a small test you never notice. In a 10,000-row loop, the rows you most want — the first few, where the pattern usually breaks — are the first to be discarded.
Sub LosesTheStart()
Dim i As Long
For i = 1 To 10000
Debug.Print i, Cells(i, 1).Value ' by the end, rows 1..9800 are gone
Next i
End Sub
When you need the whole history — every row, in order, kept after the run — Debug.Print is the wrong
tool. Open a text file and use Print # instead, which has no buffer limit and leaves a file you can
reopen (VBA Print & Write). Debug.Print is for a glance; a file is for a record.
Trap 3: printing an expression can fire real side effects
"Logging is passive" is only true when the thing you log is passive. Debug.Print evaluates its
argument, so if you print the result of a function, that function runs — with all of its consequences.
Debug.Print DeleteOldRows() ' this DELETES rows, then prints the count
Debug.Print Cells(1, 1).Value ' this is genuinely passive - just reads a value
Printing DeleteOldRows() to "see how many it would delete" actually deletes them. Keep Debug.Print
arguments to plain variables and property reads, and never route a function with side effects through it
just to inspect the return value. If you must, capture the result in a variable first, then print the
variable.
Debug.Print vs MsgBox
They look interchangeable — both show you a value — but they are opposites, and picking the wrong one is its own category of pain:
Debug.Print |
MsgBox |
|
|---|---|---|
| Blocks the macro? | No, keeps running | Yes, waits for a click |
| Where it goes | Immediate Window (dev only) | On screen, for anyone |
| In a loop | Streams thousands of lines | One modal dialog per iteration |
| History | Scrollable (last ~200 lines) | Gone the instant you click OK |
The rule writes itself: if you need to see something while developing, Debug.Print. If a person
in production needs to see something, that is a real message — MsgBox for a genuine prompt, or a
status update (VBA MsgBox). The one thing you must never do is debug a loop with
MsgBox; that is how a five-second diagnostic turns into clicking OK four hundred times.
Tip for readable output: separate values with ; to concatenate them tightly, or with , to align them
at tab stops — Debug.Print i; x; y versus Debug.Print i, x, y.
The opinion: Debug.Print is a log, not a logger
Debug.Print earns its place as the fastest way to watch values during development, and it is almost
always the right answer over MsgBox for anything that repeats. But it is a log line, not a logging
system. The moment you need the output to survive the session, carry a timestamp, or come from a macro
running on someone else's machine with no VBA editor open, you have outgrown it.
Two habits keep it honest. First, strip Debug.Print out of shipped code or gate it behind a constant like
Const DEBUG_MODE As Boolean = False — left in a hot loop it still formats strings and writes to the
buffer on every call, which is a real, measurable cost. Second, when the requirement is a durable record
rather than a glance, switch to Print # and a text file. Debug.Print's job ends the moment you close
the VBA editor; do not ask it to be your audit trail.
When the whole job is finding the bug — describe it instead
Half the time the real task is not "print this value" but "find the one row in 8,000 where the total
stops matching, and tell me what is different about it." By the time you have sprinkled Debug.Print
through a 200-line macro, re-run it, scrolled a truncated Immediate Window and reconstructed the pattern
by eye, the instrumentation has cost more than the fix.
ExcelMaster lets you state that
goal in plain English — "find every row where column E does not equal C plus D, and show me those rows" —
and it writes Python that reads the data, backs up your file first, applies the check, and hands back the
exact rows that fail. You describe the question; it does the looking.
Frequently asked questions
Where does Debug.Print output go in VBA?
To the Immediate Window in the VBA editor. Open it with Ctrl+G or View > Immediate Window. The output is only visible there — it never appears on the worksheet or in a dialog — which is why closed Immediate Window is the usual reason Debug.Print seems to do nothing.
Why is Debug.Print not showing anything?
Almost always because the Immediate Window is closed (press Ctrl+G), or because your output scrolled past
the roughly 200-line buffer, or because the macro raised an error before reaching the line. Confirm the
window is open and add a Debug.Print "reached here" marker to check the code path actually runs.
What is the difference between Debug.Print and MsgBox?
Debug.Print writes silently to the Immediate Window and lets the macro keep running; MsgBox stops the
macro with a modal dialog you must dismiss. Use Debug.Print for loops and value history during
development, and MsgBox only when a person actually needs to see or answer something.
How do I print multiple values on one line in VBA?
Separate them with a semicolon or a comma: Debug.Print i; x; y concatenates the values tightly, while
Debug.Print i, x, y aligns them at tab stops (columns). Use ; for compact rows and , for a readable
table in the Immediate Window.
Should I leave Debug.Print in production code?
No. Strip it, or gate it behind a constant such as Const DEBUG_MODE As Boolean = False. Even harmless
looking, it still evaluates its argument and writes to the capped Immediate Window buffer on every call,
which slows a hot loop. For output that must persist, log to a file with Print # instead.
Tested in
Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-09-05.
Related guides: VBA Immediate Window · VBA Breakpoint · VBA MsgBox · VBA Print & Write · VBA For Loop
