5 Powerful VS Code User Tasks That End Terminal Repetition
Table of Contents
I work on BigCommerce themes day in and day out, and for years I kept typing stencil start, npm run dev, and the same handful of build commands over and over. It is the sort of friction that does not show up in any single day, but over a year it adds up to hours of context switching between the editor and a terminal. VS Code user tasks fixed it for me with one small configuration file, and this post is the walk-through I wish I had read sooner.
This article walks through five powerful VS Code user tasks patterns I use every day: opening the global tasks.json, writing a minimal shell task, marking a dev server as a background task, binding the default build shortcut, and the presentation settings that keep the terminal pane sane. Each pattern is a small change. Stacked together they remove the part of my workflow where I switch from the editor to a terminal, find the right folder, and retype something I have typed a thousand times before.
Why Terminal Repetition Compounds Over a Year
Running stencil start takes maybe three seconds end to end: open the integrated terminal, type the command, wait for the dev server. Multiply that by ten or twenty times a day across two or three projects, and you are losing meaningful minutes a week just on the muscle memory of starting your environment.
The bigger cost is the context switch. Every trip to the terminal pulls my attention out of whatever code I was editing and into a different mental mode. VS Code user tasks erase that switch by binding the same commands to keystrokes that fire from inside the editor, without changing window focus. That is the part of the workflow that compounds most.
Workspace Tasks vs VS Code User Tasks
VS Code has two scopes for tasks, and the difference matters. Workspace tasks live in .vscode/tasks.json inside a specific project and get committed to source control. They are perfect for project-specific commands like a custom build script or a database seeder that only that repo uses.
VS Code user tasks live in a global tasks.json file stored outside any project. They are not tied to a repository, not committed to version control, and they apply across every workspace you open. They behave like personal development utilities: anywhere I open VS Code on my machine, the same five tasks are there.
Most Stack Overflow answers about tasks.json show you the workspace scope. That is the wrong file for commands you reuse across projects. If stencil start and npm run dev are the same command in every repo, those commands belong in the global file, not in a per-project one that you also have to copy around.
Pattern 1: Opening the Global tasks.json
The discoverability of VS Code user tasks is rough. The command exists but it is buried in the Command Palette. Open it with the default keybind, then run the right command, then choose the right schema option when prompted.
1. Press the Command Palette shortcut (Ctrl+Shift+P or Cmd+Shift+P on macOS)
2. Type: Tasks: Open User Tasks
3. When prompted, choose: Others
VS Code opens (or creates) the global tasks.json:
macOS: ~/Library/Application Support/Code/User/tasks.json
Linux: ~/.config/Code/User/tasks.json
Windows: %APPDATA%/Code/User/tasks.json
The first time you run this command, VS Code asks you to pick a template. Others is the right choice. The Maven, .NET, and other templates pre-populate fields you do not need. Pick the blank one and you get a clean tasks.json with the version field already filled in.
Pattern 2: The Minimal Shell Task
The simplest VS Code user task is a label, a type, and a command. Three fields. That is enough to bind any shell command to a Run Task entry inside VS Code:
{
"version": "2.0.0",
"tasks": [
{
"label": "echo hello",
"type": "shell",
"command": "echo Hello"
}
]
}
Save the file. Run Tasks: Run Task from the Command Palette and the new entry shows up. type: shell tells VS Code to run the command in your system shell (bash, zsh, PowerShell), which is what you want for almost every CLI command. The other type, process, runs a single executable without a shell — useful for invoking node directly but rarely what you want for the friction-removal use case.
Pattern 3: Background Tasks for Dev Servers
This is the field that took me longest to find. By default, VS Code assumes a task finishes after it prints output and the process exits. A dev server does the opposite: it stays running until you kill it. Without the isBackground flag, VS Code will report the task as completed prematurely, the terminal can close unexpectedly, and the file-watcher subsystem may not realise the task is still alive.
{
"label": "Stencil: Start Dev Server",
"type": "shell",
"command": "stencil start",
"isBackground": true,
"problemMatcher": []
}
The problemMatcher: [] tells VS Code there is no specific watcher pattern to look for. If you leave problemMatcher undefined on a background task, VS Code prompts you every single time you run it to choose a matcher. Setting it to an empty array silences that prompt. For VS Code user tasks that are pure dev-server commands, the empty array is the right default.
Pattern 4: The Default Build Shortcut
VS Code reserves Ctrl+Shift+B (Cmd+Shift+B on macOS) as the default build keystroke. Any task that declares itself as the default build task fires on that shortcut without you having to pick from a list. For most projects, the right default is the bundle or compile step you run before pushing — so I bind stencil bundle to it for my BigCommerce themes:
{
"label": "Stencil: Bundle Theme",
"type": "shell",
"command": "stencil bundle",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
Only one task per file can hold isDefault: true in the build group. The first declared wins if you accidentally set it on two. Once it is in place, pressing the build shortcut runs the bundle without me ever opening a Command Palette. That is the moment where VS Code user tasks stop feeling like configuration and start feeling like an editor extension.
Pattern 5: Presentation Settings That Keep You Sane
The default behaviour for VS Code tasks is to spin up a new terminal panel each time you run a task. If you run the dev server, then run a bundle, you end up with two terminals. Run a few more and the panel becomes a mess. The presentation block fixes this with four small settings:
"presentation": {
"panel": "dedicated",
"reveal": "always",
"close": false,
"clear": false
}
panel: "dedicated" reuses the same terminal for the same task instead of creating a new one. reveal: "always" focuses the terminal pane when the task starts so you see the output. close: false keeps the terminal open after the process exits, which matters for debugging a one-off failure. clear: false preserves earlier output across runs so you can scroll back through the history. With these four lines on every task, my terminal panel stays organised even after running ten tasks across a session.
When NOT to Use VS Code User Tasks
VS Code user tasks are not for every command. Three signals tell me to fall back to either workspace tasks or a plain terminal. First, anything project-specific: a one-off migration, a custom test runner, a deployment script that only matters in one repo. Those belong in workspace tasks where they ship with the project.
Second, anything I want my teammates to run the same way. Workspace tasks are version-controlled, VS Code user tasks are not, so anything that needs to be consistent across a team belongs in the project file.
Third, anything truly one-off. If I am going to type the command twice in my life, the muscle memory of typing it is faster than adding it to tasks.json. The break-even point for me is somewhere around five repetitions a month. Below that, do not bother. Above that, the tasks file pays for itself the same day. The official VS Code Tasks documentation covers the deeper edge cases (compound tasks, input variables, problem matchers) for when you outgrow the basic patterns above.
My Current Stencil tasks.json
For reference, here is the global tasks.json I run today across every BigCommerce theme project. Three tasks: the dev server, the bundle, and an npm script catch-all. Drop your own commands in following the same shape and you have the friction-removal setup running in five minutes:
{
"version": "2.0.0",
"tasks": [
{
"label": "Stencil: Start Dev Server",
"type": "shell",
"command": "stencil start",
"isBackground": true,
"presentation": {
"panel": "dedicated",
"reveal": "always",
"clear": true
},
"problemMatcher": []
},
{
"label": "Stencil: Bundle Theme",
"type": "shell",
"command": "stencil bundle",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"panel": "dedicated",
"reveal": "always"
},
"problemMatcher": []
},
{
"label": "NPM: Dev",
"type": "shell",
"command": "npm run dev",
"isBackground": true,
"presentation": {
"panel": "dedicated",
"reveal": "always"
},
"problemMatcher": []
}
]
}
None of this is a large architectural change. It is the smallest possible quality-of-life improvement: a single configuration file, five patterns, and the friction of remembering which directory to be in before running a command quietly disappears.
Watch the Full Breakdown
The full walk-through of the VS Code user tasks setup (the workspace-versus-user contrast, opening the global file, every key field with the terminal output, and the build-shortcut payoff) is in the companion video below. There is a one-minute version on YouTube Shorts as well.
For more deep dives into developer workflow, editor tooling, and the operational details that keep daily coding sane, browse the rest of the Web Development section on this site.