Step-debug Nushell scripts in VS Code — breakpoints, stepping, a five-scope variable view, rich visualizers, and interactive prompts that become native VS Code dialogs.
Quick start
- Open a
.nufile. - Set breakpoints in the gutter.
- Press F5 (no
launch.jsonneeded — the active file is debugged).
If your script's def main takes required arguments, you'll be prompted for
them at launch; you can also set "args" in launch.json. If the script has
no main, you're offered its functions to pick an entry point (or run it
top-to-bottom) — or set "entryPoint" in launch.json.
Features
Breakpoints
- Verified breakpoints: a breakpoint on a blank/comment line snaps to the next executable line.
- Conditional breakpoints — any nu expression:
$total > 4000. - Logpoints —
file {$f.name} running total {$total}prints without stopping. - Exception breakpoints ("Runtime errors" filter): pause at the raising line with the error message in the dialog. When an external command fails, its stderr tail is attached — you see what it complained, not just the exit code.
Stepping
- F10 steps a whole line; F11 steps into nu code (closures — including bodies on the same line — and custom commands).
- On builtin pipelines, F11 walks pipe stages: it stops at every command
boundary and the Pipeline scope shows
in → <command>— the exact value about to flow into that stage.
Variables — five scopes
| Scope | Contents |
|---|---|
| Locals | return (the latest expression/command result) first, then variables, custom-command parameters and flags (absent switches show false, defaults apply), and $in inside closures |
| Pipeline | in → command — the current pipe-stage input |
| Globals | nushell special variables — $nu (config/paths/pid/os-info) and $env (incl. runtime $env.X = … mutations) — as records |
| Registers | the IR evaluator's raw slots (pairs with the IR panel) |
| Process | rolling stdout/stderr tails of external commands |
Inspection is depth-unlimited (children load on demand), previews are
structured ([table 3 rows], {name: a.txt, …}, 0x[de ad …]), and
streams describe themselves (<byte stream: text from external command>).
Visualizers
Right-click any variable → Visualize:
- tables → sortable, filterable grids
- records/lists → sortable key/value and indexed tables
- binary → hex view with 1/2/4/8/16/32/64-byte grouping and LE/BE tooltips
- strings → JSON/XML auto-detected, formatted, syntax-highlighted
Visualizing a top-level variable pins it: the panel refreshes on every stop.
Watch, hover & Debug Console
Real nu expressions evaluated against the captured variables:
$files | where size > 1000 works while paused. The console can run
externals too — handy for re-running a pipeline stage to inspect data that
only exists as a stream.
Interactive prompts
input and input list become native VS Code dialogs (input box /
quick pick, --multi and --index supported). The script blocks until you
answer; Esc returns nothing.
Time-travel
Recording is on by default — just debug, then use the Step Back and
Reverse Continue toolbar buttons to walk backward through execution:
revisit any line the script ran through (even inside a command call), and see
what the variables were at that moment. It's a recorded timeline you scrub, so
you're inspecting the past, not re-running it — you can't change the past and
continue differently; stepping forward past "now" resumes real execution.
Older steps drop once the ring buffer fills (nuDap.timeTravelMaxSteps);
nuDap.timeTravel: false records only at stops. In a past view you see Locals
and Globals (Pipeline/Registers/Process are live-only).
Hot restart
The Restart button re-runs the (possibly edited) script from disk in the
same session, breakpoints intact. Enable nuDap.restartOnSave for an
edit → save → back-at-breakpoint loop.
IR panel
"Nushell Debug: Show IR" shows the compiled instruction listing of the block you're paused in, with the current instruction highlighted — updates as you step.
Settings
| Setting | Default | Description |
|---|---|---|
nuDap.nushellPath |
(bundled / PATH) | Path to a nu built with the dap feature; runs nu --dap. Empty → bundled bin/nu, else nu on PATH |
nuDap.restartOnSave |
false |
Restart the active debug session when a .nu file is saved |
nuDap.timeTravel |
true |
Record every executed line so Step Back / Reverse Continue can revisit any line; false records only at stops |
nuDap.timeTravelMaxSteps |
10000 |
Ring-buffer cap on recorded steps (Reverse goes back at most this many) |
Good to know
- The extension bundles its own nushell engine (0.114.1); scripts are
debugged against that version, not your installed
nu. - At a stop, the highlighted line has not executed yet — on
for f in $files,$fupdates when you step into the body. - Variables assigned from streaming pipelines show a stream description — reading a stream would consume the program's data.
- Closure parameters (
each {|n| …}) aren't listed in Locals (the element is visible asin);input listenand editing variables while paused are not supported yet. - Externals get NUL as stdin: a child that waits for terminal input sees EOF instead of hanging the session.
License
MIT