NPM Script Play
Run your package.json scripts straight from the editor gutter — a WebStorm-style play button next to every script, plus a state-aware run-configuration bar with colored controls.
VS Code's built-in options never quite match the WebStorm experience: the Run script CodeLens sits above the line and pushes code around, and the NPM Scripts explorer lives in a side panel away from the file you're reading. This extension puts a real, clickable ▶ in the gutter and a live run-configuration bar in the top-right corner of the editor.
Features
- Play button in the gutter — every entry under
"scripts" in a package.json gets its own ▶ to the left of the line numbers, exactly like WebStorm. Click it and the script runs. The gutter icon is live: spinner while the script runs, green ✓ when it exits cleanly, red ✗ when it fails.
- Test-file play buttons —
*.test.* and *.spec.* JavaScript/TypeScript files are indexed as runnable test files, so they also get a Testing API play button in the gutter.
- Run-configuration bar (editor title, top right) — a compact group of colored buttons, visible from any file once a workspace has scripts:
- ⌄ opens the configuration dropdown;
- green ▶ runs the current configuration — it turns into a green ↻ (restart) while the script is running;
- red ■ appears while running: one click sends Ctrl+C to the script's terminal;
- red ✗ appears when the last run failed: one click jumps to the failing output.
- Live status bar item — shows the current configuration and its state:
▶ serve, spinner while running, ✓ on success, and on failure the item turns red (✗ serve). Click it to switch configuration. Green play and red stop buttons sit right next to it.
- Exit-code aware — scripts run as VS Code tasks, so the extension gets reliable process start/end events with real exit codes: it always knows whether the process is still running, exited cleanly, or failed, and every surface (gutter, title bar, status bar) reflects it. Stopping — with the red ■, with a manual Ctrl+C typed in the terminal, or by closing the terminal — is always detected and never treated as a failure.
- Logs survive a stop — the red ■ sends a real Ctrl+C to the script's terminal: the process ends, the terminal and all its output stay open for reading. The next ▶ closes that old terminal and starts in a fresh one, so tabs never pile up. (Processes that ignore Ctrl+C get force-killed after 4 seconds.)
- Error notifications — when a script exits with a non-zero code you get a notification with Show Output and Run Again buttons (disable with
npmScriptPlay.notifyOnError).
- Package manager detection —
yarn / pnpm / bun projects are detected per package via the packageManager field or the lockfile, and scripts run with the right tool (pnpm run build, not npm run build). Override with npmScriptPlay.packageManager.
- Persistent run configurations — the picker is no longer limited to npm scripts: it includes recent selections, detected test scripts, Vite apps, the current file, debug current file, and custom shell configurations from settings.
- Smart dropdown — the configuration picker groups entries with separators for the current configuration, recently run ones (remembered per workspace), test scripts, Vite applications, file/debug actions, custom commands, and npm scripts by package. Running/failed entries are marked with their state icon.
- Dedicated terminal per script — each script runs in its own task terminal (
npm: serve, pnpm: build, …). Every run gets a clean terminal: the previous run's terminal is kept after a stop so you can read its logs, and closed automatically when you start the script again.
- Long-running scripts welcome — dev servers like
vite --host just keep running; the spinner simply keeps spinning, and ■ stops them gracefully.
- Monorepo aware — every
package.json in the workspace is picked up (node_modules excluded), each script runs in its own package folder with its own package manager.
- Live updates — add, rename or remove a script and the gutter buttons follow along as you type. Invalid JSON mid-edit is tolerated: the previous buttons stay until the file parses again.
Usage
- Open any
package.json that has a "scripts" section.
- Click the ▶ in the gutter next to the script you want to run.
- The script starts in an integrated terminal named after it (e.g.
npm: serve) and becomes the current configuration.
From then on, in any file: green ▶ (top right) re-runs it, ⌄ picks another script, red ■ stops it, and the status bar shows what's selected and its live state. Everything you launch — from the gutter or the dropdown — becomes the current configuration, remembered across reloads.
Keyboard shortcuts
| Shortcut |
Action |
Ctrl+Alt+R |
Run current configuration (or pick one the first time) |
Ctrl+Alt+C |
Stop the running configuration |
Ctrl+Alt+D |
Open the configuration dropdown |
Settings
| Setting |
Default |
Description |
npmScriptPlay.packageManager |
auto |
Package manager used to run scripts; auto detects per package (packageManager field, then lockfile). |
npmScriptPlay.notifyOnError |
true |
Notification with Show Output / Run Again when a script fails. |
npmScriptPlay.showStatusBar |
true |
Show the run configuration in the status bar. |
npmScriptPlay.runConfigurations |
[] |
Persistent custom shell commands shown in the configuration picker. |
Example custom configurations:
"npmScriptPlay.runConfigurations": [
{
"name": "API server",
"command": "npm run dev:api",
"cwd": "${workspaceFolder}",
"description": "Start the backend dev server"
}
]
How it works
VS Code's extension API does not allow arbitrary clickable gutter decorations — that's why most script runners fall back to CodeLens. The one API that does render genuinely clickable gutter play buttons is the Testing API, so this extension registers each npm script as a lightweight test item anchored to its line in package.json. That's also why script state can appear right in the gutter (spinner / ✓ / ✗), and why scripts show up grouped by package in VS Code's Testing view — a handy bonus in monorepos.
Scripts are executed through the Tasks API (vscode.tasks.executeTask): VS Code emits process start/end events with the real exit code no matter how the process ends — clean exit, crash, red ■, manual Ctrl+C, or closing the terminal. This is what keeps the state icons truthful, without depending on shell integration.
Stopping deliberately does not use TaskExecution.terminate() (which would close the whole terminal and its logs): the red ■ writes a real Ctrl+C into the task terminal instead, so the process ends exactly as if you had typed it — terminal open, logs readable. Only if the process ignores SIGINT for 4 seconds does the extension fall back to terminate().
The colored ▶ ■ ✗ in the title bar are custom SVG icons — the title area doesn't allow text, so the configuration name lives in the status bar. That's the one visual difference from WebStorm's bar.
Requirements
npm (or the detected package manager) available on your PATH.
- Gutter icons come from the testing subsystem: if you ever hid them, re-enable
testing.gutterEnabled.
Known limitations
- The first 50
package.json files found in the workspace are indexed; files inside node_modules are always skipped.
- Scripts started manually by typing
npm run … in your own terminal are not tracked — only runs launched through the extension (gutter, ▶, dropdown) are.
Release Notes
2.2.1
- Persistent run configurations now include npm scripts, detected test scripts, Vite apps, current-file runs, current-file debug sessions, and custom shell commands from settings.
- Configuration picker reorganized into current, recent, tests, Vite applications, file/debug, custom, and package script sections.
2.2.0
- Stop no longer closes the terminal: ■ now sends a real Ctrl+C, logs stay readable, with a 4s force-kill fallback for processes that ignore it. A new run replaces the old terminal with a fresh one.
2.1.0
- Rock-solid state tracking: scripts now run as VS Code tasks, with real process start/end events. Stops (■, manual Ctrl+C, closing the terminal) are always detected, and stopping keeps the terminal logs open.
2.0.0
- State-aware everything: running / success / failure tracked via shell integration and shown in the gutter, title bar, and status bar.
- Colored run-configuration bar: green ▶/↻, red ■, red ✗ with jump-to-output.
- Package manager auto-detection (npm / yarn / pnpm / bun).
- Configuration dropdown with current/recent sections and script commands.
- Error notifications, keyboard shortcuts, settings.
1.2.0
- WebStorm-style run-configuration bar: play + configuration dropdown in the editor title area, current configuration in the status bar, remembered per workspace.
1.1.0
- Extension icon and gallery branding.
- Full documentation.
1.0.0
- Initial release: gutter play buttons for all
package.json scripts, dedicated reusable terminals, live re-parsing on edit, multi-package workspaces.
Made by Able Srl.
| |