A macro is a JavaScript or TypeScript script executed within the context of a VS Code extension, with full access to the VS Code extensibility APIs. Macros let you automate tasks, customize your development workflow, or prototype extension behavior—all without the overhead of building and maintaining a full extension.
Under the hood, macros run inside Node.js VM sandboxes. Each macro executes in its own isolated data context but shares the same process. A limitation of this model is that macros can't be forcefully terminated; instead, cancellation tokens provide a cooperative mechanism for graceful shutdown.
TypeScript transpilation is transparent and performed on-demand, designed to provide a low‑friction experience.
- Getting Started
- Commands
- Debugging
- Development
- Manage Macros
- Run Macros
- Macro Explorer View
- Macro REPL
- Development
-
Create a new macro file.
- Option 1: Use the Macros: New Macro command, or the corresponding buttons in the Macro Explorer.
- Option 2: Create an untitled document, with
javascriptortypescriptlanguage. - Option 3: Ask the
@macrosChat agent to create a macro for you.
ℹ️ Save your macro files using a
.macro.jsor.macro.tsextension. These enable UI controls, IntelliSense, and other macro-specific features. -
Write your macro code.
- You can use the Macros: Fill File with Template command in an existing editor.
- See Available References.
Example: "Hello, World!" macro
vscode.window.showInformationMessage("Hello, world!");
Example: Async "Hello, World!" macro
async function main() { const yes = { title: 'Yes' }; const no = { title: 'No', isCloseAffordance: true }; let answer; do { answer = await vscode.window.showInformationMessage( `Hello, World!. Close this dialog?`, { modal: true }, yes, no); } while (answer !== yes); } main()
-
From the Command Palette, use the Macros: Run Active Editor as Macro command to execute your macro. Alternatively, on untitled
javascriptortypescripteditors, those with*.macro.jsor*.macro.tsnames or macro files under a macro library, use the equivalent Run Macro or Debug Macro buttons available on the editor title bar.
-
Use the Macro Explorer to request specific or all instances for a given macro to stop.
-
Use the Macros: Show Running Macros command to request a specific instance to stop.
A macro sandbox cannot be forcefully terminated. Instead, a cancellation request is sent via the __cancellationToken variable. To support cancellation, this token must be properly wired into all asynchronous code and macro logic.
If a macro does not respond to the cancellation request, it will continue running. In such cases, you can use the Developer: Restart Extension Host command to restart all extensions, or simply restart VS Code to stop the macro. While this is not ideal, it provides a fallback to recover from unresponsive or runaway macros. Note that this approach does not implicitly terminate external processes started by the macro.
Workspace Trust Startup macros are disabled in untrusted workspaces.
Adding startup macros lets you customize your environment from the moment VS Code starts. Since extensions are restarted when opening a new workspace, these customizations can also be scoped per workspace.
Setting up a startup macro is easy:
-
In the Macro Explorer, use the Set as Startup Macro action from your macro's context menu. You can unset it later using Unset as Startup Macro.
-
Alternatively, update the
macros.startupMacrossetting directly in the Settings editor.
Once you've set up a startup macro, here are a few things to keep in mind:
- Paths may include tokens like
${workspaceFolder}or${userHome}for dynamic resolution. - The
macros.startupMacrossetting is additive across Global, Workspace, and Workspace Folder scopes. - Paths pointing to missing or empty files are silently ignored — see the Macros log for details.
Startup macros let you define behavior similar to an extension’s activate method. For teardown support, use the __disposables global variable to ensure proper disposal when the workspace changes or the extension reloads.
You can bind the macros.run command to a keyboard shortcut, passing as argument the path to the macro to run. This must be configured directly in your keybindings.json file, however. See the VS Code documentation for details.
-
Use the Preferences: Open Keyboard Shortcuts (JSON) command to open the
keybindings.jsonfile. -
Add a keybinding for the
macros.runcommand:- Pass the path to the macro file as argument
${userhome}and${workspaceFolder}tokens are supported
Example: Keybinding definition
[ { "key": "Shift+Alt+X", "command": "macros.run", "args": "${userhome}/macros/references.macro.js", "when": "editorTextFocus" } ]
See Debugging a Macro for additional information.
- Macros: Debug Active File as Macro: debug current editor as a macro (document will be saved before running).
- Macro: Debug Macro: select a macro file to debug. Provides access to configured
macros.sourceDirectories.
-
Macros: Create REPL: create a REPL terminal to evaluate JavaScript or TypeScript code whose context matches the one used by running macros.
-
Macros: Setup Source Directory for Development: adds or updates optional files used to improve IntelliSense on macro files. This action is run automatically in the background when saving a
.macro.jsor.macro.tsfile, provided thatmacros.sourceDirectories.verifyis enabled.
- Macros: Fill File with Template: initialize an existing file with example macro content.
- Macros: New Macro: creates a new file with example macro content.
- Macros: Show Running Macros: view and manage running macros.
- Macros: Run Active File as Macro: run current editor as a macro (document will be saved before running).
- Macros: Rerun Last Macro: execute the most recently run macro.
- Macros: Run Macro: select a macro to run. Provides access to macros in configured
macros.sourceDirectoriesdirectories.
The Macro Explorer provides a central management view for macros. You can use the Macros: Show Macro Explorer command to bring it into view.
-
Macro Library Folders: configure macro folders, browse their contents, and quickly add, delete, or move macro files around using drag-and-drop.
- "Temporary": this is a virtual library node that shows all untitled macro documents allowing to easily manage in-memory macros.
-
Macros: edit, run, or debug macros with a once-click.
-
Macro Run Instances: see active runs. Stop existing ones directly from the view. This is more convenient than the Macros: Show Running Macros command but it does not replace it as in-memory runs do not have a representation here.
- This view shows options used when a given instance was created.
The REPL is a powerful interactive component that lets you:
- Evaluate JavaScript or TypeScript code in the same context used when running macros
- Inspect the current state of VS Code, including active editors, workspace folders, and extension APIs
- Quickly execute custom actions, test macro logic, or simply run JS/TS code.
You can start a new REPL using the Macros: Create REPL from the Command Palette or using the corresponding icon on the Macros Explorer view. You can have as many REPLs as you need, each one is fully isolated.
- Use
.tsor.jsto switch between TypeScript and JavaScript modes - Use
.helpto view all available REPL commands and utilities
The following references are available from the global context of your macro:
vscode: symbol that provides access to the VS Code APIs.macros: symbol that provides access to this extension's API (see Macros API).require: method that allows load Node.js libraries. Version is same as your installed VS Code's (seeAboutoption).- Other:
atob,btoa,clearInterval,clearTimeout,crypto,fetch,global,require,setInterval,setTimeout.
-
log: Provides access to the Macros log output channel, allowing macros to write log entries as needed. -
macro: Current macro.uri: URI of the currently executin macro. It can beundefinedif running from an in-memory buffer.
-
window: Provides access to UI-related APIs. Provides access to UI-related APIs for managing predefined macro views.-
getTreeViewId(requestor: MacroRunId): string | undefined: Claims an availabletreeviewID for the given macro run. Returnsundefinedif none are available. -
getWebviewId(requestor: MacroRunId): string | undefined: Claims an availablewebviewID for the given macro run. Returnsundefinedif none are available. -
releaseTreeViewId(requestor: MacroRunId, id: string): boolean: Releases a previously claimedtreeviewID. Returnstrueif successful. -
releaseWebviewId(requestor: MacroRunId, id: string): boolean: Releases a previously claimedwebviewID. Returnstrueif successful.
These tokens do not form part of contexts shared when
@macro:persistentis used as they are different from session to session.__cancellationToken: a CancellationToken used by th extension to notify about a stop request. See Stopping a Macro.__disposables: an array for adding Disposable instances, which will be automatically disposed of when the macro completes.__runId: Id of the current macro execution session.__startup: Whether current macro execution session was triggered during startup.
-
Views such as sidebars and panels cannot be created dynamically—they must be declared in the extension's package.json manifest. To work around this limitation, the extension predefines a Macros view container (macrosViews) that includes a fixed set of generic treeview and webview views.
Macro-backed tree view ("Tree View" template)
The following views are statically registered and available for use:
macrosView.treeview1throughmacrosView.treeview5— fortreeview-based UIsmacrosView.webview1throughmacrosView.webview5— forwebview-based UIs
Avoid hardcoding view IDs unless absolutely necessary—there’s no enforcement mechanism, so conflicts between macros may occur. Additionally, the predefined ID pool may expand in the future, meaning macros with hardcoded values could end up competing for a limited subset.
While macros can hardcode and use these IDs directly, this approach becomes fragile as macro libraries grow—multiple macros may attempt to use the same view, causing conflicts.
To avoid this, macros can dynamically claim an available view ID using the following APIs:
macros.window.getTreeViewId(requestor: MacroRunId): string | undefined
macros.window.getWebviewId(requestor: MacroRunId): string | undefinedIf no view ID is available, these methods return undefined so make sure to account for such case.
Once a macro is finished using a view, it can release the ID explicitly using the following APIs:
macros.window.releaseTreeViewId(requestor: MacroRunId, id: string): boolean
macros.window.releaseWebviewId(requestor: MacroRunId, id: string): booleanAlternatively, all claimed IDs are automatically released when the macro completes. This includes REPL sessions, as each sessions is equivalent to a macro.
Views are disabled by default. After claiming an ID, you must enable the corresponding view using a context key (notice the id is suffixed with .show):
Example: Showing a view
const viewId = macros.window.getTreeViewId();
...
vscode.commands.executeCommand('setContext', `${viewId}.show`, true);
Be sure to reset the context when the macro finishes, there is no automatic tracking and any leftover context values will be effective until VS Code is restarted.
Example: Hiding a view
const viewId = macros.window.getWebviewId();
...
vscode.commands.executeCommand('setContext', `${viewId}.show`, false);
An option is added to macro file as a comment in the form //@macro:«option»[,…«option»]. The following options are available:
persistent: All invocations of the macro use the same execution context so global variables persist across runs. Use theReset ContextCodeLens to reinitialize context.retained: An instance of the macro will remain active until explicitly stopped, e.g., using the Macros: Show Running Macros command. This removes the need to await__cancellationToken.onCancellationRequested(or similar signal) to keep the macro's services and listeners running.singleton: Only one instance of the macro may run at a time; additional invocations fail.
// @macro:singleton
// Example: Hello World!
vscode.window.showInformationMessage("Hello, world!");Any URL in a macro file pointing to a .d.ts file will automatically receive a code action, Download .d.ts, enabling you to download the file directly to the macro's parent folder. This simplifies adding type definitions to support IntelliSense in your macros.
For GitHub URLs containing /blob/, the extension offers special handling by converting them to their raw equivalent. For example: https://github.com/Microsoft/vscode/blob/main/extensions/git/src/api/git.d.ts is automatically handled as https://github.com/Microsoft/vscode/raw/refs/heads/main/extensions/git/src/api/git.d.ts.
For all other URLs, a standard HTTP GET request is sent to download the file.
Debugging a macro leverages VS Code's extension debugging story since the macros are run in the context of this extension: it launches a new Extension Host instance on which the debugger has been attached fom the original instance. You manually execute the macro under the appropriate context on the new instance (e.g. this might require re-opening the workspace you started from) but set breakpoints and step through code from the original instance.




