Back to Blog
Software EngineeringJuly 2, 20264 min read

VS Code Extension Development: Building Custom Debugging Commands

Learn VS Code extension development with the VS Code Command API. Build custom debugging workflows to boost your developer productivity tools today.

VS CodeExtension DevelopmentTypeScriptAutomationProductivityDebuggingTooling

During a particularly brutal debugging session last month, I found myself manually clearing caches, restarting a specific local proxy, and re-attaching the debugger for the tenth time in an hour. It was tedious, error-prone, and a massive drain on my focus. I realized that if I was doing it manually, I was wasting precious time that could be spent actually solving the bug.

That’s when I finally dove into VS Code extension development to automate the process. By building a custom command that handles the lifecycle of my debugging session, I managed to cut my "restart-to-test" cycle from roughly 45 seconds down to about 8 seconds.

Why the VS Code Command API?

You might already be using VS Code Task Runner: Automate CI/CD Workflows Like a Pro for simple build scripts. While tasks are great for one-off commands, they lack the fine-grained control you get when you start building your own extensions.

Using the VS Code Command API, you can interact directly with the editor's internal state, manage active debug sessions, and even manipulate the UI. It’s the difference between running a shell script and having a native plugin that understands your project’s context.

Setting Up Your First Command

To get started, ensure you have the yo code generator installed. Run npx yo code and select "New Extension (TypeScript)".

Once your project is scaffolded, your package.json is where you register the command. It’s how VS Code knows your command exists:

JSON
"contributes": {
  "commands": [{
    "command": "extension.restartDebugSession",
    "title": "Restart Debugger with Cache Clear"
  }]
}

Now, hook this up in extension.ts. You’ll want to import vscode and register the command logic.

TYPESCRIPT
import * as vscode from CE9178">'vscode';

export function activate(context: vscode.ExtensionContext) {
  let disposable = vscode.commands.registerCommand(CE9178">'extension.restartDebugSession', async () => {
    // Logic to clear cache goes here
    await vscode.commands.executeCommand(CE9178">'workbench.action.debug.stop');
    
    // Give the process a moment to release ports
    await new Promise(resolve => setTimeout(resolve, 500));
    
    vscode.commands.executeCommand(CE9178">'workbench.action.debug.start');
  });

  context.subscriptions.push(disposable);
}

The Wrong Turn: Over-Engineering

I initially tried to watch the filesystem for changes to trigger the debug restart. It was a disaster. Every time my build process wrote a temporary file, the debugger would kill itself and restart in a loop. I ended up with a high CPU usage warning and a headache.

The lesson? Keep your custom debugging workflows explicit. Triggering them manually via a Command Palette shortcut or a status bar item is much more reliable than trying to guess when the developer wants a restart. If you want to isolate these, remember that you can always Mastering VS Code Profiles: Automate Your Development Workflow to keep these tools away from your standard coding environment.

Comparison: Tasks vs. Extensions

When deciding how to automate, consider the complexity of the state you need to manage.

FeatureVS Code TasksCustom Extension
Ease of SetupLowHigh
State ManagementLimitedFull API access
UI InteractionNoneHigh (Webviews/Menus)
Lifecycle HooksBasicAdvanced/Custom

Scaling Your Productivity

Once you have the basics down, you can start building more powerful developer productivity tools. I eventually added a notification that shows the duration of the restart process. It’s a small touch, but it provides instant feedback on whether the system is hanging.

If you find yourself frequently switching between these configurations, you might also look at how Developer productivity: Why I stopped writing clean code first to ensure that your tooling doesn't become a distraction itself. The goal is to spend less time configuring VS Code automation and more time shipping features.

FAQ

Can I run these commands on a timer? Yes, but be careful. Using setInterval inside an extension can lead to performance degradation. It’s better to use an event-based approach whenever possible.

Do I need to publish the extension to use it? Not at all. You can install your own extension locally by packaging it with vsce package and running code --install-extension <path-to-vsix>, or simply by keeping it in your .vscode/extensions folder during development.

What if my debugger hangs? Use vscode.debug.getActiveDebugSession() to check if a session is alive before attempting to stop it. This prevents the command from throwing errors if you run it when nothing is happening.

I’m still refining my own setup, particularly around handling asynchronous cleanup tasks that don't always signal "done" to the OS. If you hit a wall with the API, check the official VS Code Extension API documentation—it’s surprisingly readable once you get past the initial learning curve. Don't let the complexity stop you; the time you save will pay for the development effort within a week.

Similar Posts