Writing your own extension

VS Code · Expert · 15 min

A small custom extension can automate a team-specific workflow that no marketplace extension covers.

Extensions are Node.js packages written in TypeScript or JavaScript. Scaffold one with the Yeoman generator: npx --package yo --package generator-code -- yo code. It creates:

  • package.json with the manifest: engines.vscode (minimum version), main (entry file), and a contributes section declaring commands, settings, keybindings, menus and more. Contributed commands activate the extension automatically when invoked.
  • src/extension.ts exporting activate(context) and optionally deactivate().

Inside activate, use the vscode API: vscode.commands.registerCommand, vscode.window.activeTextEditor, vscode.window.showInformationMessage, vscode.workspace.getConfiguration, and editing via editor.edit or WorkspaceEdit. Push every disposable (commands, listeners) into context.subscriptions so it is cleaned up on deactivation.

Press F5 to launch an Extension Development Host, a second VS Code window with your extension loaded; breakpoints in your code work immediately. The generator also sets up tests run with @vscode/test-cli.

To share it, package with npx @vscode/vsce package (creates a .vsix you can install with code --install-extension file.vsix) or publish to the Marketplace under a publisher account. Keep activation narrow and work asynchronous; the extension host is shared with every other extension.

Example

// src/extension.ts  (package.json contributes command "wc.count", title "Count Words")
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  const cmd = vscode.commands.registerCommand('wc.count', () => {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
      vscode.window.showWarningMessage('No active editor');
      return;
    }
    const sel = editor.selection;
    const text = editor.document.getText(sel.isEmpty ? undefined : sel);
    const words = text.split(/\s+/).filter(Boolean).length;
    vscode.window.showInformationMessage(`Words: ${words}`);
  });
  context.subscriptions.push(cmd);
}

export function deactivate() {}

Remember

  • package.json contributes declare commands, settings, menus
  • activate() registers handlers; push disposables to context.subscriptions
  • F5 opens an Extension Development Host; vsce packages a .vsix

Watch out for

  • Activating on every startup ("*") when a command or language activation event would do.

Check yourself

  1. What does pressing F5 in a generated extension project do?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: code.visualstudio.com/api/get-started/your-first-extension