01 / Title
Deck 11 Β· IDE extensions / dev tooling

Build your own IDE extension. Idea to publish.

The real-world path from "my editor should do that" to a published extension β€” what extensions actually are, the five VS Code surfaces that cover almost every idea, the gotchas the tutorials don't warn you about, the Azure publishing detour nobody mentions, and an honest field guide to Zed, JetBrains, and Neovim.

Weekend-scale One .vsix β†’ two stores VS Code + Cursor + Windsurf + VSCodium Real gotchas, paid in afternoons
02 Β· the itch

Every developer has one.

That small thing your editor almost does. You've tolerated it for months. Maybe years.

The claimYou can fix that yourself β€” in a weekend, without being an expert. An extension isn't a mystical artifact maintained by people smarter than you. It's a small program plus a form that tells the editor where to plug in. If you can write a script, you can write an extension.
The case this deck followsA CLI tool with a local web UI for PR review. The UI was fine β€” but using it meant a terminal, a command, a browser tab, a context switch. The fix: a VS Code extension that starts the server, shows the numbers in the sidebar, and embeds the whole UI in an editor tab.
03 Β· the mental model

Strip the branding β€” every extension system answers three questions.

1 Β· Where does it plug in?

A manifest β€” a small config file where you declare: I add a command, a keyboard shortcut, a sidebar panel, a setting.

2 Β· When does it wake up?

Editors don't run your code constantly. It loads when something you declared happens: your command runs, a file type opens, startup finishes.

3 Β· What can it touch?

An API the editor hands your code β€” and a sandbox deciding how far your code can reach.

For the non-developersThink browser extensions, but for the program people write code in. The editor is a phone, extensions are apps, the marketplace is the app store. Same shape, different device β€” and just like phone apps, most extensions are tiny: one command, one panel, one quality-of-life fix.
04 Β· anatomy

VS Code in one diagram β€” two files do almost everything.

Diagram showing how a VS Code extension plugs into the editor: the package.json manifest declares contributions and activation events, src/extension.ts holds activate and deactivate functions, both feed into the extension host process, which surfaces them as Command Palette entries, status bar items, sidebar panels, and webview tabs
The whole mental model β€” manifest + one source file β†’ extension host β†’ editor surfaces. Click to zoom.
Why it's safe to experimentYour code runs in a separate process the editor babysits β€” the extension host. If your extension crashes, the editor doesn't. You cannot brick your setup. Worst case, you disable it. The barrier to trying is much lower than it looks.
05 Β· taxonomy

Extensions come in nine shapes. Know them, place your idea.

ShapeWhat it doesYou've met it as
Command / toolAdds a button that does a thingThe shape this deck builds
Syntax highlighterColorizes a language the editor doesn't knowGrammars for niche languages
ThemeRestyles the whole editorOne Dark Pro + ten thousand cousins
Snippet packThree letters expand into thirty linesrafce β†’ a full React component
FormatterRewrites code to one style on savePrettier, Black
LinterThe squiggles while you typeESLint
Language serverReal intelligence β€” autocomplete, go-to-def, hover docsrust-analyzer, Pyright
DebuggerBreakpoints and stepping inside the editorDebug adapters
BridgeA doorway to a tool that lives outside the editorDocker, Remote SSH, GitLens
The shortcutThemes and snippet packs are just JSON. No code, no API, no extension host β€” a palette or a pile of templates in a manifest. Plenty of people earn "published extension author" without writing a line of TypeScript. That's an honest way in.
06 Β· before you write code

Most failed extensions die here β€” not in the code.

Two minutes of honesty saves a weekend.

βœ“ Probably good

A repeated action β€” same 3–4 steps daily. A command + a keybinding turns it into one keypress.

Glanceable information β€” whatever you'd open a browser tab to check, made ambient in a status bar or sidebar row.

A bridge β€” a tool you love living outside the editor. The extension doesn't replace it; it hands you a doorway.

βœ— Probably bad

Settings or keybindings already do it. Embarrassing numbers of "extensions" re-implement built-in config. Search settings first.

An existing extension already does it. Search the marketplace twice β€” once for what it's called, once for what it does.

It's a whole app. Needs its own navigation, accounts, a database? It should be a web app with an extension as a thin doorway.

07 Β· the thin-client principle

Embed, don't rebuild.

The mathThe extension's actual jobs are the cheap ones: start the thing, show the numbers, open the right place. That's a weekend. A native re-implementation is a quarter.
08 Β· VS Code path Β· setup

The fifteen-minute skeleton.

# Node.js installed, empty folder: npx --package yo --package generator-code -- yo code
  1. The official scaffolder β€” name, identifier, TypeScript (say yes) β€” hands you a working extension with a sample command.
  2. Open the folder, press F5. A second window appears β€” the Extension Development Host β€” with your extension loaded.
  3. Ctrl+Shift+P β†’ type your command's name β†’ run it. A notification pops. That's the whole loop.
You'll live in this loopEdit β†’ F5 β†’ test in the host window β†’ Developer: Reload Window. No emulator downloads, no signing certs, no device registration β€” compare that to any other platform you've developed for.
09 Β· VS Code path Β· package.json

Half the work is filling in a form.

You don't code a palette entry or a shortcut β€” you declare them, and the editor builds them for you.

{ "name": "deploy-buddy", "publisher": "yourname", "engines": { "vscode": "^1.85.0" }, "contributes": { "commands": [ { "command": "deploybuddy.deploy", "title": "Deploy current branch" } ], "keybindings": [ { "command": "deploybuddy.deploy", "key": "ctrl+alt+d", "when": "editorTextFocus" } ], "configuration": { "properties": { "deploybuddy.environmentUrl": { "type": "string", "default": "https://staging.example.com" } } } } }
10 Β· VS Code path Β· extension.ts

Your first command β€” the whole code side.

import * as vscode from "vscode"; export function activate(context: vscode.ExtensionContext) { const disposable = vscode.commands.registerCommand( "deploybuddy.deploy", async () => { const editor = vscode.window.activeTextEditor; if (!editor) return vscode.window.showErrorMessage("Open a file first"); const branch = await vscode.commands.executeCommand("git.currentBranch"); vscode.window.showInformationMessage(`Deploying ${branch}…`); // your actual work here }, ); context.subscriptions.push(disposable); } export function deactivate() {}
11 Β· VS Code path Β· the API

The API is huge. You'll use five surfaces.

SurfaceWhat it isUse it for
Command PaletteCtrl+Shift+P entriesAnything the user does occasionally
Quick PickshowQuickPick() β€” the fuzzy dropdownPicking one thing: environments, branches, tickets
Status barcreateStatusBarItem() β€” bottom-bar textOne number, always visible: build status, server health
Sidebar panelcreateTreeView() β€” activity-bar treeStructured info: multiple items, live counts
WebviewcreateWebviewPanel() β€” a browser tab inside the editorAnything visual: dashboards, embedding a web UI
If you wrap a local web toolThe webview is the finish line: point an iframe at http://localhost:PORT β€” Chromium treats localhost as trustworthy, so http doesn't trip security rules β€” and your entire UI now lives in an editor tab. Reuse one panel and repoint its src on navigation, instead of spawning a tab per click. Embed, don't rebuild β€” slide 07 in code.
12 Β· gotchas Β· rendering

Lessons that cost an afternoon each β€” rendering.

13 Β· gotchas Β· the webview sandbox

The webview is a locked-down browser β€” and it fails silently.

14 Β· gotchas Β· processes & drift

The classics: zombies, Windows, and drift.

15 Β· testing

F5 is for your eyes. Test in the real editor.

npm install --save-dev @vscode/test-electron # package.json: "test": "node out/test/runTest.js" β€” the scaffold has this
16 Β· shipping Β· the file

Start with just a file β€” the .vsix.

npm install -g @vscode/vsce vsce package # β†’ your-extension-1.0.0.vsix code --install-extension your-extension-1.0.0.vsix
Do not skip past thisA .vsix file is a completely legitimate end state. Team tooling, an internal extension that will never be public, a personal scratch extension β€” package it, drop it in a shared drive or a GitHub release, done. Software that serves one team well is not a failure.
17 Β· shipping Β· the main store

Publishing is one command β€” behind two accounts.

  1. Create a publisher on the Visual Studio Marketplace β€” an ID that permanently identifies you and your extensions.
  2. Create a PAT on Azure DevOps. Yes, Azure β€” the Marketplace's auth lives there. Token scoped to All accessible organizations + Marketplace β†’ Manage β€” anything else gets you a bare 403 that doesn't tell you why.
  3. The absurd part: creating an Azure DevOps org can require linking an Azure subscription β€” and even a free-tier Azure account wants a card for identity verification. To publish a free extension. The single most common place publishing stalls out.
Calendar noteGlobal PATs retire December 1, 2026 β€” the going-forward path is Entra ID auth (workload identity federation in CI, vsce publish --azure-credential). Setting up fresh? Do it the new way from day one and skip the token-renewal treadmill.
Marketplace ruleWhat it means for you
Versions strictly increasePublished a broken version? You can't overwrite it β€” fix it by shipping the next version
The listing is a snapshotREADME, icon, description update only when you publish. No "refresh listing" button
No SVGs in listingsIcon, badges, README images β€” raster only, https URLs
Removal is foreverUnpublishing removes it from every user; names stay reserved. Prefer leaving an old version up
18 Β· shipping Β· the second store

One extra step β€” five more editors.

Marketplace terms allow Microsoft builds of VS Code only. Cursor, Windsurf, VSCodium, Gitpod, Theia β€” all built on VS Code's open-source core, all banned from the main store. They share a second store: Open VSX. And it takes the same .vsix you already built.

Diagram showing one vsix file flowing to three destinations: the VS Code Marketplace serving VS Code users, Open VSX serving Cursor, Windsurf, VSCodium, Gitpod, Theia and Antigravity users, and direct Install-from-VSX reaching any editor without a store, with Open VSX also noted as usable by VS Code itself
The solo-developer distribution strategy β€” build one .vsix, publish it twice. Click to zoom.
19 Β· beyond VS Code

The rest of the editor world β€” the honest state.

VS Code familyZedJetBrainsNeovim
LanguageTypeScript / JSRust β†’ WASMKotlin / JavaLua
Custom UIWebviews, panels, status barNone yet (open RFC)Full IDE-grade UIFull TUI
DistributionMarketplace + Open VSXPR to central repoJetBrains MarketplaceGit repos
First resultAn eveningAn evening (non-UI)A weekend or twoAn evening
ReachEvery VS Code-based editorZed usersAll JetBrains IDEsNeovim users
20 Β· the decision

Which one first? Reach per effort.

Start absurdly smallOne command that does one thing you actually do daily. Ship that, use it for a week, let the extension tell you what it wants to become next β€” the review extension started as "start the server without typing a command"; the sidebar counts, the embedded tab, the quick picks were all pull, added because daily use kept asking. Never seen one ruined by starting too small. The big-bang ones β€” plenty.
21 Β· the path from here

The gap is shorter than it looks.

  1. Today: npx --package yo --package generator-code -- yo code, press F5, change the sample command's message to something that makes you smile. You're now an extension developer.
  2. This week: pick the one repetitive thing you actually do daily β€” make a command for it, add a keybinding in the manifest.
  3. When it's useful: vsce package and install the .vsix properly β€” you'll feel the difference the first time it's just there after a restart.
  4. If the world needs it: publish β€” Marketplace for VS Code, Open VSX for everything VS Code-shaped. The Azure detour is a rite of passage, not a sign you're doing it wrong.

The most useful software you'll ever write might be the kind only you needed. There's exactly one way to find out.

Deck 11 Β· Build Your Own IDE Extension β€” companion to blog B-28

Deck Controls

SpaceNext slide
Previous slide
Home / EndFirst / last slide
19Jump to slide N
OOverview grid
GGo to slide
FToggle fullscreen
BBlackout screen
?Toggle this help
Click left / right halfPrev / next slide
Swipe (touch)Prev / next slide
Press ? or Esc to close

All slides β€” click to jump