VS Code is a shell. Every useful feature a data creator relies on — Python language server, dbt LSP, Databricks Connect debugger, Copilot — comes from an extension. Understanding the ecosystem is a prerequisite for running a paved path that does not drift, leak, or rot.

What an extension is

An extension is a package that registers contributions against VS Code's extension API. Contributions fall into categories:

An extension can contribute any combination. The Databricks extension, for example, contributes a tree view, commands, a task provider, and a debug adapter.

Where extensions live

Three locations, different trust levels:

SourceWho publishesTrust
Visual Studio Marketplace (marketplace.visualstudio.com)Microsoft and third partiesDefault. Microsoft operates light review.
Open VSX (open-vsx.org)CommunityUsed by VSCodium, Theia, and some VS Code forks. Less curated.
VSIX sideloadAnyoneTrust is entirely on you. Sometimes necessary for internal extensions or air-gapped shops.

VS Code (the Microsoft build) defaults to the Marketplace. Cursor and most VS Code forks default to Open VSX. Extension IDs overlap between the two but publishers can and do differ.

The supply chain you inherit

Installing an extension runs untrusted code on your laptop. Extensions have full filesystem access, network access, and terminal access. A compromised extension can exfiltrate your SSH keys, AWS credentials, and source code before you open the next file.

This has happened. In 2024, a popular theme extension shipped a malicious update that harvested developer credentials. In 2025, a "dbt helper" extension was flagged for stealing warehouse credentials from ~/.dbt/profiles.yml. The pattern repeats.

Warning

Every extension you install is a supply-chain dependency. Treat the list the same way you treat requirements.txt: pinned, reviewed, and audited. If you would not paste a random pip install URL from the internet, do not click-install a random extension either.

Version pinning and reproducibility

By default, VS Code auto-updates extensions when new versions appear. That is fine for a hobby setup and catastrophic for a team that needs reproducible builds.

Three mitigations, in increasing rigor:

  1. Workspace recommendations. .vscode/extensions.json with a recommendations array. VS Code prompts new contributors to install them. It does not pin versions but gets everyone to the same list.
  2. Extension pack. A published VS Code extension whose sole contribution is extensionPack — a list of other extensions. Installing the pack installs the list. The pack version itself can be pinned; new entries require a new pack release.
  3. Paved-path setup script. An idempotent script that runs code --install-extension <id>@<version> for every extension. Checked into the paved-path repo. Run on every onboarding and in CI for devcontainer builds.

Tip

Combine (2) and (3). Publish an Extension Pack for day-to-day contributor use. Use the setup script for devcontainers and CI where reproducibility is non-negotiable.

Disabling auto-update

In user settings:

{
  "extensions.autoUpdate": false,
  "extensions.autoCheckUpdates": true
}

Auto-check stays on so you see what is available. Auto-update goes off so the act of updating is a deliberate action. Review release notes before clicking.

Reading an extension's permissions

VS Code does not have a mature permission-prompt system the way browsers do. Extensions ask for broad scopes and get them. Evaluate an extension before installing:

Publisher reputation

The safe publishers as of 2026:

Anyone else warrants scrutiny. "I found this handy extension yesterday" is the beginning of most supply-chain incidents.

Governance in an org

A responsible org extension policy has three layers:

Important

Do not run the allow-list as a bottleneck. If proposals take weeks to review, engineers route around the policy by installing extensions anyway. Aim for a two-day review SLA and staff it.

Devcontainers and extensions

Devcontainer extensions live in the devcontainer's customizations.vscode.extensions array. They install inside the container on first open. Since the container is reproducible, extensions are effectively pinned through it — if you rebuild the devcontainer, you rebuild the extension set.

Combine devcontainers with the paved-path Extension Pack: the devcontainer installs the Pack, the Pack installs the extensions. One source of truth for the full set.

When to write your own

Platform teams sometimes publish internal extensions:

The barrier is low — yo code scaffolds a TypeScript extension — but the ongoing maintenance is not. Default to configuring marketplace extensions well before writing new ones.

Anti-patterns

The failure modes that trip up teams:

The maintenance cadence

A healthy Extension Pack gets reviewed quarterly. Questions to answer:

A paved-path pack that has not been reviewed in a year is a paved-path pack that no longer reflects reality.

See also