Documentation
Topics Overview Overview Tutorial Intro Videos Agents Editor Overview Quickstart Staging & Committing Branches & Worktrees Repositories & Remotes Merge Conflicts Collaborate on GitHub Troubleshooting FAQ Get Started Terminal Basics Terminal Profiles Shell Integration Appearance Advanced Debugging Debug Configuration Tasks Testing Integrated Browser Port Forwarding Guides & Tutorials Test-Driven Development Test Web Apps with Browser Tools Overview Enterprise Policies AI Settings Extensions Telemetry Updates Overview VS Code for the Web SSH SSH Tutorial Tunnels Dev Containers WSL WSL Tutorial GitHub Codespaces VS Code Server Linux Prerequisites Tips and Tricks FAQ GitHub Copilot Setup Linux macOS Windows Raspberry Pi Network Portable Mode Additional Components Uninstall Languages & Runtimes Extension DocsOn this page there are 19 sections
Integrate with External Tools via Tasks
Lots of tools exist to automate tasks like linting, building, packaging, testing, or deploying software systems. Examples include the TypeScript Compiler, linters like ESLint and TSLint as well as build systems like Make, Ant, Gulp, Jake, Rake, and MSBuild.
These tools are mostly run from the command line and automate jobs inside and outside the inner software development loop (edit, compile, test, and debug). Given their importance in the development life cycle, it is helpful to be able to run tools and analyze their results from within VS Code. Tasks in VS Code can be configured to run scripts and start processes so that many of these existing tools can be used from within VS Code without having to enter a command line or write new code. Workspace or folder specific tasks are configured from the tasks.json file in the .vscode folder for a workspace.
Extensions can also contribute tasks using a Task Provider, and these contributed tasks can add workspace-specific configurations defined in the tasks.json file.
Note: Task support is only available when working on a workspace folder. It is not available when editing single files.
TypeScript Hello World
Let's start with a simple "Hello World" TypeScript program that we want to compile to JavaScript.
Create an empty folder "mytask", generate a tsconfig.json file and start VS Code from that folder.
function sayHello(name: string): void { console.log(`Hello ${name}!`); } sayHello('Dave');Pressing ⇧⌘B (Windows, Linux Ctrl+Shift+B) or running Run Build Task from the global Terminal menu show the following picker:
The first entry executes the TypeScript compiler and translates the TypeScript file to a JavaScript file. When the compiler has finished, there should be a HelloWorld.js file. The second entry starts the TypeScript compiler in watch mode. Every save to the HelloWorld.ts file will regenerate the HelloWorld.js file.
You can also define the TypeScript build or watch task as the default build task so that it is executed directly when triggering Run Build Task (⇧⌘B (Windows, Linux Ctrl+Shift+B)). To do so, select Configure Default Build Task from the global Terminal menu. This shows you a picker with the available build tasks. Select tsc: build or tsc: watch and VS Code will generate a tasks.json file. The one shown below makes the tsc: build task the default build task:
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "type": "npm", "script": "lint", "problemMatcher": ["$eslint-stylish"] } ] }This instructs VS Code to scan the output of the npm lint script for problems using the ESLint stylish format.
For Gulp, Grunt, and Jake, the task auto-detection works the same. Below is an example of the tasks detected for the vscode-node-debug extension.
Tip: You can run your task through Quick Open (⌘P (Windows, Linux Ctrl+P)) by typing 'task', Space and the command name. In this case, 'task lint'.
Task auto detection can be disabled using the following settings:
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "Run tests", "type": "shell", "command": "./scripts/test.sh", "windows": { "command": ".\\scripts\\test.cmd" }, "group": "test", "presentation": { "reveal": "always", "panel": "new" } } ] }The task's properties have the following semantic:
- label: The task's label used in the user interface.
- type: The task's type. For a custom task, this can either be shell or process. If shell is specified, the command is interpreted as a shell command (for example: bash, cmd, or PowerShell). If process is specified, the command is interpreted as a process to execute.
- command: The actual command to execute.
- windows: Any Windows specific properties. Will be used instead of the default properties when the command is executed on the Windows operating system.
- group: Defines to which group the task belongs. In the example, it belongs to the test group. Tasks that belong to the test group can be executed by running Run Test Task from the Command Palette.
- presentation: Defines how the task output is handled in the user interface. In this example, the Integrated Terminal showing the output is always revealed and a new terminal is created on every task run.
- options: Override the defaults for cwd (current working directory), env (environment variables), or shell (default shell). Options can be set per task but also globally or per platform. Environment variables configured here can only be referenced from within your task script or process and will not be resolved if they are part of your args, command, or other task attributes.
- runOptions: Defines when and how a task is run.
- hide: Hides the task from the Run Task Quick Pick, which can be useful for elements of a compound task that are not independently runnable.
You can see the full set of task properties and values with IntelliSense in your tasks.json file. Bring up suggestions with Trigger Suggest (⌃Space (Windows, Linux Ctrl+Space)) and read the descriptions on hover or with the Read More... ('i') flyout.
You can also review the tasks.json schema.
Shell commands need special treatment when it comes to commands and arguments that contain spaces or other special characters like $. By default, the task system supports the following behavior:
- If a single command is provided, the task system passes the command as is to the underlying shell. If the command needs quoting or escaping to function properly, the command needs to contain the proper quotes or escape characters. For example, to list the directory of a folder containing spaces in its name, the command executed in bash should look like this: ls 'folder with spaces'.
- If you want to control how the argument is quoted, the argument can be a literal specifying the value and a quoting style. The example below uses escaping instead of quoting for an argument with spaces.
If you specify "dependsOrder": "sequence", then your task dependencies are executed in the order they are listed in dependsOn. Any background/watch tasks used in dependsOn with "dependsOrder": "sequence" must have a problem matcher that tracks when they are "done". The following task runs task Two, task Three, and then task One.
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "type": "npm", "script": "lint", "problemMatcher": ["$eslint-stylish"], "presentation": { "reveal": "never" } } ] }You can also mix custom tasks with configurations for detected tasks. A tasks.json that configures the npm: run lint task and adds a custom Run Test tasks looks like this:
{ "task.allowAutomaticTasks": "off" }You can also change your choice at any time using the Tasks: Manage Automatic Tasks command from the Command Palette, and selecting between Allow Automatic Tasks and Disallow Automatic Tasks for the current workspace.
Customizing auto-detected tasks
As mentioned above, you can customize auto-detected tasks in the tasks.json file. You usually do so to modify presentation properties or to attach a problem matcher to scan the task's output for errors and warnings. You can customize a task directly from the Run Task list by pressing the gear icon to the right to insert the corresponding task reference into the tasks.json file. Assume you have the following Gulp file to lint JavaScript files using ESLint (the file is taken from https://github.com/adametry/gulp-eslint):
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "type": "gulp", "task": "default", "problemMatcher": [] } ] }Usually you would now add a problem matcher (in this case $eslint-stylish) or modify the presentation settings.
Processing task output with problem matchers
VS Code can process the output from a task with a problem matcher. Problem matchers scan the task output text for known warning or error strings, and report these inline in the editor and in the Problems panel. VS Code ships with several problem matchers 'in-the-box':
- TypeScript: $tsc assumes that file names in the output are relative to the opened folder.
- TypeScript Watch: $tsc-watch matches problems reported from the tsc compiler when executed in watch mode.
- JSHint: $jshint assumes that file names are reported as an absolute path.
- JSHint Stylish: $jshint-stylish assumes that file names are reported as an absolute path.
- ESLint Compact: $eslint-compact assumes that file names in the output are relative to the opened folder.
- ESLint Stylish: $eslint-stylish assumes that file names in the output are relative to the opened folder.
- Go: $go matches problems reported from the go compiler. Assumes that file names are relative to the opened folder.
- CSharp and VB Compiler: $mscompile assumes that file names are reported as an absolute path.
- Lessc compiler: $lessc assumes that file names are reported as absolute path.
- Node Sass compiler: $node-sass assumes that file names are reported as an absolute path.
You can also create your own problem matcher, which we'll discuss in a later section.
Binding keyboard shortcuts to tasks
If you need to run a task frequently, you can define a keyboard shortcut for the task.
For example, to bind Ctrl+H to the Run tests task from above, add the following to your keybindings.json file:
{ "label": "TypeScript compile", "type": "shell", "command": "tsc ${file}", "problemMatcher": ["$tsc"] }Similarly, you can reference your project's configuration settings by prefixing the name with ${config:. For example, ${config:python.formatting.autopep8Path} returns the Python extension setting formatting.autopep8Path.
Below is an example of a custom task configuration, which executes autopep8 on the current file using the autopep8 executable defined by the python.formatting.autopep8Path setting:
{ "label": "Run Node", "type": "process", "windows": { "command": "C:\\Program Files\\nodejs\\node.exe" }, "linux": { "command": "/usr/bin/node" } }Valid operating properties are windows for Windows, linux for Linux, and osx for macOS. Properties defined in an operating system specific scope override properties defined in the task or global scope.
Global tasks
Task properties can also be defined in the global scope. If present, they will be used for specific tasks unless they define the same property with a different value. In the example below, there is a global presentation property, which defines that all tasks should be executed in a new panel:
"tasks": [ { "label": "PowerShell example 1 (unexpected escaping)", "type": "shell", "command": "Get-ChildItem \"Folder With Spaces\"" }, { "label": "PowerShell example 2 (expected escaping)", "type": "shell", "command": "Get-ChildItem", "args": ["Folder With Spaces"] }, { "label": "PowerShell example 3 (manual escaping)", "type": "shell", "command": "& Get-ChildItem \\\"Folder With Spaces\\\"" } ]Changing the encoding for a task output
Tasks frequently act with files on disk. If these files are stored on disk with an encoding different than the system encoding, you need to let the command executed as a task know which encoding to use. Since this depends on the operating system and the shell used, there is no general solution to control this. Below are advice and examples on how to make it work.
If you need to tweak the encoding, you should check whether it makes sense to change the default encoding used by your operating system or at least change it for the shell you use by tweaking the shell's profile file.
If you only need to tweak it for a specific task, then add the OS-specific command necessary to change the encoding to the tasks command line. The following example is for Windows using code page of 437 as its default. The task shows the output of a file containing Cyrillic characters and therefore needs code page 866. The task to list the file looks like this assuming that the default shell is set to cmd.exe:
helloWorld.c:5:3: warning: implicit declaration of function ‘prinft’We want to produce a problem matcher that can capture the message in the output and show a corresponding problem in VS Code. Problem matchers heavily rely on regular expressions. The section below assumes you are familiar with regular expressions.
Tip: We have found the RegEx101 playground, which has an ECMAScript (JavaScript) flavor, to be a great way to develop and test regular expressions.
A matcher that captures the above warning (and errors) looks like this:
{ "version": "2.0.0", "tasks": [ { "label": "build", "command": "gcc", "args": ["-Wall", "helloWorld.c", "-o", "helloWorld"], "problemMatcher": { "owner": "cpp", "fileLocation": ["relative", "${workspaceFolder}"], "source": "gcc", "pattern": { "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5 } } } ] }Running it inside VS Code and pressing ⇧⌘M (Windows, Linux Ctrl+Shift+M) to get the list of problems gives you the following output:
Note: The C/C++ extension includes problem matchers for GCC so there is no need to define our own.
There are a couple more properties that can be used inside a pattern. These are:
- location - If the problem location is line or line,column or startLine,startColumn,endLine,endColumn, then our generic location match group can be used.
- endLine - The match group index for the problem's end line. Can be omitted if no end line value is provided by the compiler.
- endColumn - The match group index for the problem's end column. Can be omitted if no end column value is provided by the compiler.
- code - The match group index for the problem's code. Can be omitted if no code value is provided by the compiler.
You can also define a problem matcher that captures only a file. To do so, define a pattern with the optional kind attribute set to file. In this case, there is no need to provide a line or location property.
Note: A functional pattern must at least provide a match group for file and message if the kind property is set to file. If no kind property is provided or the kind property is set to location, a function pattern must provide a line or location property as well.
Note: The problem matcher only parses output from the given command. If you want to parse output written to separate file (e.g. a log file), make the command that you run print out lines from the separate file before it finishes executing.
Defining a multiline problem matcher
Some tools spread problems found in a source file over several lines, especially if stylish reporters are used. An example is ESLint; in stylish mode it produces output like this:
"pattern": [ { "regexp": "^Error:\\s+(.*)$", "message": 1 }, { "regexp": "^.*$" }, { "regexp": "^\\s+at\\s+(.*):(\\d+)$", "file": 1, "line": 2 } ]The following problem pattern matches the output from ESLint in stylish mode - but still has one small issue that we need to resolve next. The code below has a first regular expression to capture the file name and the second to capture the line, column, severity, message, and error code:
test.js 1:0 error Missing "use strict" statement strict 1:9 error foo is defined but never used no-unused-vars 2:5 error x is defined but never used no-unused-vars 2:11 error Missing semicolon semi 3:1 error "bar" is not defined no-undef 4:1 error Newline required at end of file but not found eol-last ✖ 6 problems (6 errors, 0 warnings)The pattern's first regular expression will match "test.js", the second "1:0 error ...". The next line "1:9 error ..." is processed but not matched by the first regular expression and so no problem is captured.
To make this work, the last regular expression of a multiline pattern can specify the loop property. If set to true, it instructs the task system to apply the last pattern of a multiline matcher to the lines in the output as long as the regular expression matches.
The information captured by the first pattern, which in this case matches test.js, will be combined with each of the subsequent lines that match the loop pattern to create multiple problems. In this example, six problems would be created.
Here is a problem matcher to fully capture ESLint stylish problems:
{ "type": "npm", "script": "watch", "problemMatcher": { "base": "$tsc-watch", "applyTo": "allDocuments" }, "isBackground": true }Other modifiable problem matcher properties include background, fileLocation, owner, pattern, severity, and source.
Background / watching tasks
Some tools support running in the background while watching the file system for changes and then triggering an action when a file changes on disk. With Gulp such functionality is provided through the npm module gulp-watch. The TypeScript compiler tsc has built in support for this via the --watch command line option.
To provide feedback that a background task is active in VS Code and producing problem results, a problem matcher has to use additional information to detect these state changes in the output. Let's take the tsc compiler as an example. When the compiler is started in watch mode, it prints the following additional information to the console:
12:32:35 PM - File change detected. Starting incremental compilation... src/messages.ts(276,9): error TS2304: Cannot find name 'candidate'. 12:32:35 PM - Compilation complete. Watching for file changes.Looking at the output shows the following pattern:
- The compiler runs when File change detected. Starting incremental compilation... is printed to the console.
- The compiler stops when Compilation complete. Watching for file changes. is printed to the console.
- Between those two strings problems are reported.
- The compiler also runs once the initial start (without printing File change detected. Starting incremental compilation... to the console).
To capture this information, a problem matcher can provide a background property.
For the tsc compiler, an appropriate background property looks like this:
{ "version": "2.0.0", "tasks": [ { "label": "watch", "command": "tsc", "args": ["--watch"], "isBackground": true, "problemMatcher": { "owner": "typescript", "fileLocation": "relative", "pattern": { "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", "file": 1, "location": 2, "severity": 3, "code": 4, "message": 5 }, "background": { "activeOnStart": true, "beginsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - File change detected\\. Starting incremental compilation\\.\\.\\.", "endsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - Compilation complete\\. Watching for file changes\\." } } } ] }Next steps
That was tasks - let's keep going...
- tasks.json Schema - You can review the full tasks.json schema and descriptions.
- Basic Editing - Learn about the powerful VS Code editor.
- Code Navigation - Move quickly through your source code.
- Language Support - Learn about our supported programming languages, both shipped with VS Code and through community extensions.
- Debugging - Debug your source code directly in the VS Code editor.
Common questions
Can a task use a different shell than the one specified for the Integrated Terminal?
Yes. You can use the "terminal.integrated.automationProfile.*" setting to set the shell that will be used for all automation in VS Code, which includes Tasks.
{ "version": "2.0.0", "windows": { "options": { "shell": { "executable": "cmd.exe", "args": [ "/d", "/c" ] } } }, ...Can a background task be used as a prelaunchTask in launch.json?
Yes. Since a background task will run until killed, a background task on its own has no signal that it has "completed". To use a background task as a prelaunchTask, you must add an appropriate background problemMatcher to the background task so that there is a way for the task system and debug system to know that the task "finished".
Your task could be:
{ "name": "Launch Extension", "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", "args": ["--extensionDevelopmentPath=${workspaceRoot}"], "stopOnEntry": false, "sourceMaps": true, "outFiles": ["${workspaceRoot}/out/src/**/*.js"], "preLaunchTask": "npm: watch" }For more on background tasks, go to Background / watching tasks.
Why do I get "command not found" when running a task?
The message "command not found" happens when the task command you're trying to run is not recognized by your terminal as something runnable. Most often, this occurs because the command is configured as part of your shell's startup scripts. Tasks are run as non-login and non-interactive, which means that the startup scripts for your shell won't be run. nvm in particular is known to use startup scripts as part of its configuration.
There are several ways to resolve this issue:
- Make sure your command is on your path and doesn't require startup scripts to get added to your path. This is the most thorough way to solve the problem, and is the recommended solution.
- You can make a one-off fix for your task to run as login or interactive. This is not recommended, as it can have other consequences. However, it can also be a quick and easy fix for a single task. Below is an example of a task that does this with bash as the shell: