Publish VS Code Extensions to Open VSX: 12 Steps [2026]

Cursor shipped version 3.21.16 on September 19, 2026, and it still doesn’t pull extensions from Microsoft’s Visual Studio Code Marketplace. If you maintain a VS Code extension and want Cursor’s growing user base to find it, publishing to the VS Code Marketplace alone leaves a real gap. Cursor’s Extensions panel searches Open VSX, the vendor-neutral registry maintained by the Eclipse Foundation, through a proxy at marketplace.cursorapi.com. This tutorial walks through scaffolding an extension, packaging it with @vscode/vsce, and publishing the same build to both the VS Code Marketplace and Open VSX so it shows up whether a developer is running stable VS Code 1.138 or the latest Cursor build. By the end you’ll have a working extension, a reusable GitHub Actions pipeline that publishes to both registries on every tagged release, and a checklist for the parts of this process that trip up first-time publishers.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

Why publishing to the VS Code Marketplace alone isn’t enough anymore

Cursor is built on the same Code OSS foundation as VS Code, which is why most extensions and keyboard shortcuts feel identical between the two editors. What’s different is where each one goes to fetch third-party extensions. VS Code queries Microsoft’s official Marketplace by default. Cursor does not, because Microsoft’s Marketplace terms of service restrict its use to Microsoft’s own products, so forks like Cursor, VSCodium, Gitpod, and Eclipse Theia all route extension search and install requests through Open VSX instead. Cursor specifically proxies that traffic through its own endpoint at marketplace.cursorapi.com, which applies automated malware and supply-chain scanning before an extension is offered for install inside the app.

That single architectural fact changes how you should think about distribution. If your extension only exists on the VS Code Marketplace, Cursor users can’t find it through the built-in Extensions panel at all. Their only path is downloading a .vsix file manually and running Cursor’s “Install from VSIX” command, which is a much higher-friction ask than a search-and-click install. Publishing the same build to Open VSX removes that friction and, because Open VSX also feeds VSCodium, Gitpod, Theia, and other Code OSS-based editors, it multiplies your reach well beyond just Cursor’s install base.

There’s a subtlety worth flagging early: the same publisher.extension identifier can point to different code, or a different maintainer entirely, on Open VSX versus the Microsoft Marketplace, because the two registries don’t share ownership records. Before you install someone else’s extension across editors, or before you claim a name for your own, it pays to check both registries rather than assume a match. It’s also worth noting that Cursor ships first-party replacements, built by Anysphere, for a handful of widely used extensions that never made it onto Open VSX. If you’re building something that overlaps with, say, a popular linter integration or a remote-development tool, check whether Cursor already bundles an equivalent before assuming a gap exists.

VS Code Marketplace vs. Open VSX: what actually differs for a publisher

Both registries accept the same .vsix file and the same package.json manifest, but the accounts, tooling, and review process behind each one are separate systems built by different organizations. The table below is what you’re actually signing up for on each side before you touch a single publish command.

FactorVS Code MarketplaceOpen VSX
Operated byMicrosoftEclipse Foundation
CLI tool@vscode/vsceovsx
Account neededAzure DevOps organizationEclipse Foundation account linked to GitHub
Auth methodPersonal Access Token (PAT), migrating to Entra ID workload identity federation before Dec. 1, 2026Access token generated on open-vsx.org
Identity unitPublisher IDNamespace
Automated reviewMarketplace content policy checksSecret detection, blocklist screening, namespace similarity analysis
Consumed byVS Code (default)Cursor, VSCodium, Gitpod, Eclipse Theia, and other Code OSS forks
Cost to publishFreeFree
Popularity signalInstall count and star ratingsDownload count, no star-rating system

The practical takeaway is that neither registry is a superset of the other. Skipping Open VSX means Cursor’s roughly extension-search-driven install funnel never sees your work. Skipping the VS Code Marketplace means you’re invisible to the much larger base of developers still on mainstream VS Code. Maintaining a presence on both isn’t optional busywork, it’s the only way to cover both audiences without asking users to manually sideload a file.

Prerequisites and exact versions

Everything in this walkthrough works with free accounts on both registries. You don’t need a paid Azure DevOps subscription or a commercial Eclipse Foundation membership to publish an extension, open source or otherwise. Here’s what to have installed and set up before Step 1.

Tool or accountVersion / requirementWhat it’s for
Node.js20.x LTS or newerRuns vsce and ovsx via npm/npx
Visual Studio Code1.138 (stable, released Aug. 26, 2026) or newerLocal development and the Extension Development Host
Cursor3.21.16 (released Sept. 19, 2026) or newerVerifying your extension loads and searches correctly
@vscode/vsceLatest version via npmPackages and publishes to the VS Code Marketplace
ovsx CLILatest version via npxPublishes the same package to Open VSX
Yeoman + generator-codeLatest via npmScaffolds the starter extension project
Azure DevOps organizationFree tierRequired to generate a Marketplace Personal Access Token
Eclipse Foundation accountFreeRequired to publish to Open VSX
GitHub account and repoFreeHosts your source and runs the CI publishing pipeline

If you already have an extension published on the VS Code Marketplace and just want to add Open VSX distribution, you can skip straight to Step 8. Everything from Step 1 through Step 7 covers building and shipping a new extension from scratch, which is useful context even if you’re retrofitting an existing project. Either way, budget around 90 minutes for a first run through every step, most of which goes to waiting on account verification emails rather than actual command execution.

Step 1: Scaffold your extension with Yeoman

Microsoft maintains an official Yeoman generator that produces a working TypeScript extension skeleton, complete with a test harness and a launch configuration for debugging. Install it globally and run it once.

npm install -g yo generator-code
yo code

The interactive prompt asks for an extension type (choose “New Extension (TypeScript)” unless you have a specific reason for JavaScript), a display name, an identifier, a description, whether to initialize a git repository, and which package manager to use. Accept the defaults for a first pass. The generator drops a ready-to-run project with a sample command already wired up in extension.ts, which is enough to test the full publish pipeline before you write any real functionality. Treat this scaffold as disposable scratch space rather than your production extension until you’ve confirmed the entire dual-publish flow works end to end; it’s much cheaper to debug a publishing hiccup on a placeholder “Hello World” command than on months of real feature work.

Step 2: Structure package.json for two marketplaces

Both the VS Code Marketplace and Open VSX read metadata from the exact same manifest file, so you only maintain one package.json. A few fields matter more than the generator’s defaults suggest, because Open VSX validates some of them more strictly than Microsoft’s Marketplace does.

{
  "name": "my-extension",
  "displayName": "My Extension",
  "description": "Short, specific description of what it does.",
  "version": "0.1.0",
  "publisher": "your-publisher-id",
  "license": "MIT",
  "icon": "icon.png",
  "engines": {
    "vscode": "^1.90.0"
  },
  "categories": ["Programming Languages"],
  "repository": {
    "type": "git",
    "url": "https://github.com/your-org/my-extension.git"
  },
  "activationEvents": [],
  "main": "./out/extension.js",
  "contributes": {
    "commands": [
      { "command": "myExtension.helloWorld", "title": "Hello World" }
    ]
  }
}

The license field is the one most first-time publishers skip, and it’s the one Open VSX cares about most. Without it, your extension listing shows no license badge and some Open VSX scanning steps treat it as unlicensed, which can slow down approval. The repository field matters for the same reason: Open VSX’s automated review checks it as part of confirming you actually own what you’re publishing. Keep icon pointed at a real PNG file bundled inside your project (128x128px is the safe size), since both marketplaces render it directly from the packaged .vsix rather than fetching it from an external URL. The categories array is validated against a fixed list shared by both manifest schemas, so an unrecognized category name will get silently dropped rather than causing a hard error, which is worth checking for after your first publish rather than assuming it took.

Step 3: Test your extension in the Extension Development Host

Before packaging anything, confirm the extension actually works. Open the project folder in either VS Code or Cursor and press F5. Both editors implement the same Extension Development Host mechanism, since it’s inherited from the shared Code OSS codebase, so a debug session started in Cursor behaves identically to one started in VS Code: a new window opens with your extension loaded, breakpoints in your TypeScript source hit normally, and the Debug Console shows any console.log output. Run the command you registered in contributes.commands from the Command Palette (Ctrl+Shift+P or Cmd+Shift+P) to confirm activation works, then use the Developer: Reload Window command to pick up code changes without restarting the whole debug session.

This step matters more than it looks like on paper, because it’s the only point in the whole workflow where you’re testing source code directly rather than a packaged artifact. Bugs introduced by bundling, minification, or an incorrect main path in package.json won’t show up here, which is exactly why the next few steps exist. If your extension interacts with Cursor’s AI features, such as reading from the editor’s selection or responding to inline suggestions, test those interactions specifically in a Cursor-launched debug session rather than assuming a VS Code test covers it, since Cursor layers additional UI state on top of the shared editor core.

Step 4: Install and configure @vscode/vsce

The command-line tool for packaging and publishing to the VS Code Marketplace is maintained by Microsoft under the scoped npm package @vscode/vsce (the old unscoped vsce package is deprecated in favor of this one). Install it globally so the vsce command is available anywhere.

npm install -g @vscode/vsce
vsce --version

If you’d rather not install anything globally, every vsce command in this guide also works prefixed with npx, which downloads and runs the current version on demand. That’s the approach the GitHub Actions pipeline in Step 11 uses, since CI runners shouldn’t accumulate global packages between jobs.

Step 5: Create a publisher and Personal Access Token

Publishing to the VS Code Marketplace requires a publisher identity and an Azure DevOps Personal Access Token, even though you’re not using Azure DevOps for anything else. Set both up before you try to run vsce publish for the first time.

  • Go to the Visual Studio Marketplace publisher management page and click “Create publisher.”
  • Enter a unique publisher ID (this becomes part of your extension’s URL and must match the publisher field in package.json) and a display name.
  • In the Azure DevOps portal, open your organization, go to User settings, then Personal access tokens, and create a new token.
  • Set the organization scope to “All accessible organizations” and, under Custom defined scopes, select “Marketplace (Manage).”
  • Copy the token immediately. Azure DevOps only shows it once.
  • Run vsce login your-publisher-id and paste the token when prompted.

One deadline worth putting on your calendar: Microsoft is retiring global Personal Access Tokens for Marketplace publishing on December 1, 2026, in favor of Microsoft Entra ID with workload identity federation. If you’re setting this up now, the PAT approach above still works through that date, but plan to migrate your CI pipeline’s authentication method before then rather than after your token stops working. Note the deadline down in whatever calendar your team actually checks, since a silently expired token tends to surface as a confusing CI failure weeks later rather than an obvious error on the day it lapses.

Step 6: Package your extension into a VSIX

A .vsix file is the actual distributable unit for both marketplaces and it’s the same file format Cursor’s “Install from VSIX” command consumes directly, so packaging it locally first lets you sanity-check the final artifact before it goes anywhere public.

vsce package

This produces something like my-extension-0.1.0.vsix in your project root. Add a .vscodeignore file if you haven’t already, so the package doesn’t ship your source TypeScript, test files, or node_modules alongside the compiled output:

.vscode/**
.vscode-test/**
src/**
.gitignore
.yarnrc
vsc-extension-quickstart.md
**/tsconfig.json
**/.eslintrc.json
**/*.map
**/*.ts

Install the generated .vsix locally in either editor via Extensions: Install from VSIX to confirm the packaged version behaves the same as it did in the debug host. This catches the class of bug where something works fine from source but breaks once bundled, usually because a required file got excluded or a path assumption doesn’t hold after packaging.

Step 7: Publish to the Visual Studio Code Marketplace

With a publisher, a token, and a tested .vsix in hand, publishing is a single command.

# Publish the current version as-is
vsce publish

# Or bump the version automatically and publish in one step
vsce publish patch
vsce publish minor
vsce publish major

Two version-gated features are worth knowing about if your extension needs them: pre-release extensions (a separate update channel from your stable releases) require users to be on VS Code 1.63.0 or newer to install, and publishing platform-specific builds, useful if your extension bundles native binaries for different operating systems, requires vsce version 1.99.0 or newer. Neither is required for a typical TypeScript-only extension, but both matter if you’re wrapping a compiled dependency.

Step 8: Set up your Eclipse account and Open VSX namespace

Open VSX runs on separate infrastructure from Microsoft’s Marketplace, maintained by the Eclipse Foundation, so it has its own account and namespace system that doesn’t automatically recognize anything you did in Step 5.

  • Register an account at accounts.eclipse.org. Your GitHub username on this account must match exactly what you use to log into open-vsx.org, or the two systems won’t link.
  • Log into open-vsx.org using GitHub, then connect your Eclipse account from your open-vsx.org profile page.
  • Agree to the Publisher Agreement, which is a one-time step required before your first publish.
  • Generate an access token under Settings, then Access Tokens, on open-vsx.org, and store it securely.
  • Claim a namespace, which is the Open VSX equivalent of a publisher ID, using the ovsx CLI in the next step.

Namespaces on Open VSX are independent from publisher IDs on the VS Code Marketplace. You can use the same string for both, which keeps your extension’s identity consistent across editors, but nothing forces that consistency automatically, so pick your name carefully on the first registry before repeating it on the second. If your organization already publishes other extensions under a shared brand name, claim that same namespace here even if you only have one extension ready today, so future extensions land under a consistent identity rather than scattered publisher names.

Step 9: Publish to Open VSX with ovsx

The ovsx npm package is the CLI counterpart to vsce, purpose-built for Open VSX. Because it’s typically run with npx rather than installed globally, there’s no separate install step.

# Claim your namespace once, before your first publish
npx ovsx create-namespace your-publisher-id -p YOUR_OVSX_TOKEN

# Publish an already-packaged .vsix
npx ovsx publish my-extension-0.1.0.vsix -p YOUR_OVSX_TOKEN

# Or build and publish directly from source
npx ovsx publish -p YOUR_OVSX_TOKEN

# Add --yarn if your project uses Yarn instead of npm
npx ovsx publish --yarn -p YOUR_OVSX_TOKEN

Open VSX runs its own automated review on every submission: secret detection scans your packaged files for accidentally committed credentials, a blocklist check screens for known-malicious packages, and a namespace similarity analysis flags names that look like they’re impersonating an existing popular extension. A clean, correctly licensed extension with a unique name typically clears all three checks within minutes. If your extension gets flagged, the CLI output tells you which check failed, and you’ll need to resolve it (usually a naming change or a genuine secret you need to rotate) before the publish succeeds.

Step 10: Confirm your extension shows up inside Cursor

Open Cursor and go to the Extensions panel with Ctrl+Shift+X on Windows and Linux or Cmd+Shift+X on macOS. Search for your extension by name or publisher/namespace. Propagation from a successful Open VSX publish to Cursor’s search index isn’t always instant, it can take anywhere from a few minutes to a couple of hours, so if it doesn’t appear right away, search for it directly on open-vsx.org first to confirm the publish itself succeeded before assuming something’s broken on Cursor’s end.

Once it appears, verify the listing shows the correct publisher name, icon, description, and version number, then install it and reload the window to confirm activation works the same way it did in your local Extension Development Host testing. This is your final sanity check before telling anyone the extension is live.

Step 11: Automate dual publishing with GitHub Actions

Manually running two separate publish commands for every release is exactly the kind of step that gets forgotten under deadline pressure, which is how extensions end up out of sync between registries. A single GitHub Actions workflow triggered on tag pushes removes that risk entirely.

name: Publish Extension

on:
  push:
    tags:
      - 'v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Compile
        run: npm run compile

      - name: Package extension
        run: npx @vscode/vsce package

      - name: Publish to VS Code Marketplace
        run: npx @vscode/vsce publish -p ${{ secrets.VSCE_PAT }}

      - name: Publish to Open VSX
        uses: HaaLeo/publish-vscode-extension@v1
        with:
          pat: ${{ secrets.OVSX_PAT }}
          registryUrl: https://open-vsx.org

Add VSCE_PAT and OVSX_PAT as repository secrets in GitHub before your first tag push (Settings, then Secrets and variables, then Actions, then New repository secret). From this point forward, cutting a release is a matter of bumping the version in package.json, committing, tagging with something like v0.2.0, and pushing the tag. Both marketplaces receive the same build from the same commit, which eliminates the entire category of bug where the VS Code Marketplace and Open VSX quietly drift onto different versions.

Step 12: Manage version bumps and updates across both registries

Once the CI pipeline from Step 11 is in place, version management becomes a single source of truth problem rather than a two-registry coordination problem. The version number lives in exactly one place, package.json, and both publish commands read from it. The discipline that matters going forward is never running vsce publish or ovsx publish manually against a version number that doesn’t match what’s committed to your repository, since that’s how the two registries end up presenting different code under the same version label to users.

For teams with more than one maintainer, add each contributor as a publisher on both the Azure DevOps organization and the Open VSX namespace’s access list, rather than sharing a single person’s token in CI secrets. Both registries support multiple maintainers per publisher or namespace specifically to avoid a bus-factor-of-one situation where releases stall because one person is unavailable.

Verifying a publish programmatically with each registry’s API

Waiting around in a GUI to confirm a release went out isn’t necessary once you know both registries expose plain HTTP endpoints for extension metadata. This is worth wiring into a post-release check, either as a manual habit or as a follow-up job in the same GitHub Actions pipeline, so you get a fast, scriptable answer to “did the last release actually land” instead of eyeballing two different websites.

# Check the latest published version on Open VSX
curl -s "https://open-vsx.org/api/your-publisher-id/my-extension" | grep -o '"version":"[^"]*"'

# Check the latest published version on the VS Code Marketplace
curl -s -X POST "https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json;api-version=3.0-preview.1" \
  -d '{"filters":[{"criteria":[{"filterType":7,"value":"your-publisher-id.my-extension"}]}],"flags":914}' \
  | grep -o '"version":"[^"]*"' | head -1

Comparing the version string returned by each call against the tag you just pushed is a quick way to catch the exact failure mode this guide keeps warning about: one registry publishing successfully while the other silently fails, whether from an expired token, a network hiccup in CI, or a review hold on Open VSX’s side. If you’re maintaining more than a couple of extensions, a small script that loops both checks across all of them and reports mismatches is worth the twenty minutes it takes to write.

When a public registry isn’t the right fit: private and enterprise distribution

Not every extension belongs on a public marketplace. Internal tooling that references proprietary APIs, or an extension built for a client engagement, often needs to reach a specific team without being searchable by anyone else. Both registries technically support unlisted or private distribution, but the far simpler route for a small team is skipping public registries entirely and distributing the packaged .vsix directly.

Host the .vsix file in a private location your team already has access to, an internal artifact repository, a private GitHub release, or even a shared drive, and have teammates install it through the same Extensions: Install from VSIX command used earlier in this guide, in either VS Code or Cursor. For a slightly more automated version of the same idea, the GitHub Actions workflow from Step 11 can be adapted to attach the packaged .vsix as a build artifact or a GitHub Release asset instead of, or alongside, the two public publish steps, giving you a private distribution channel that updates automatically without ever touching the VS Code Marketplace or Open VSX review process.

Common pitfalls when publishing to two extension marketplaces

Most of the failures publishers hit the first time they try dual distribution trace back to a handful of repeat offenders. Watch for these specifically before you assume something deeper is broken.

  • Skipping the license field. Open VSX treats a missing license field in package.json as unlicensed, which suppresses the license badge on your listing and can slow down the automated review.
  • Publisher ID and namespace mismatch. Nothing technically requires your VS Code Marketplace publisher ID and your Open VSX namespace to match, but letting them diverge creates two different-looking brand identities for the same extension across editors.
  • Baking in Marketplace-only assumptions. Code that calls a Microsoft Marketplace-specific API or endpoint will silently fail for users who installed via Open VSX, since that install path never touches Microsoft’s infrastructure.
  • Only testing the debug host, never the packaged .vsix. Bugs from an incorrect .vscodeignore, a missing compiled file, or a wrong main path only show up once you package and install the real artifact, not while running from source in F5.
  • Letting your Azure DevOps PAT lapse. With global PATs retiring December 1, 2026, a token generated today will need to be replaced with Entra ID-based authentication before that date, or your CI pipeline’s Marketplace publish step will start failing with no obvious error until you check.
  • Choosing a name the similarity scanner flags. Open VSX’s namespace similarity analysis exists to catch typosquatting, so a name that’s one character off from an existing popular extension can get held up for manual review even when your intent is entirely legitimate.

What a clean dual publish looks like

Here’s roughly what successful output looks like from each half of the pipeline, so you know what to expect versus what signals a real failure.

$ npx @vscode/vsce publish
Executing prepublish script 'npm run vscode:prepublish'...
DONE  Published your-publisher-id.my-extension v0.2.0.

$ npx ovsx publish my-extension-0.2.0.vsix -p ***
Fetched icon from my-extension-0.2.0.vsix
Fetched README from my-extension-0.2.0.vsix
Fetched CHANGELOG from my-extension-0.2.0.vsix
Extracted metadata
Scan complete: no secrets, no blocklist matches, no namespace conflicts
Published [email protected] to https://open-vsx.org

Inside Cursor’s Extensions panel, a fresh publish shows your display name, publisher/namespace, version number matching what you just pushed, and an install count starting at zero. If the version number in Cursor’s listing doesn’t match the version you just published to Open VSX, that’s a strong signal the propagation delay mentioned in Step 10 hasn’t finished yet rather than a genuine failure.

Troubleshooting: 8 issues and fixes

  • “Missing publisher name” from vsce. Add or correct the publisher field in package.json so it matches your registered publisher ID exactly.
  • vsce login fails with a 401 error. Your Azure DevOps PAT either has the wrong scope (it needs “Marketplace (Manage)”) or was created under a specific organization instead of “All accessible organizations.”
  • Extension doesn’t appear in Cursor’s search after an Open VSX publish. Search open-vsx.org directly first to confirm the publish succeeded, then wait for propagation, which can take up to a couple of hours.
  • ovsx publish fails with “namespace not found.” You skipped the create-namespace command, or the token you’re using doesn’t belong to the account that owns that namespace.
  • Icon doesn’t render on the extension card. The icon path in package.json must point to a PNG file bundled inside the .vsix, not an absolute URL to an external image host.
  • README looks fine on the VS Code Marketplace but breaks on Open VSX. Relative image links in your README resolve against a different base path on Open VSX, so convert them to absolute GitHub raw URLs.
  • vsce reports it can’t find README.md during publish. This is usually a case-sensitivity issue on Linux CI runners; make sure the filename referenced in your project matches the actual file’s case exactly.
  • “Version already exists” on your second publish attempt. You bumped the version for one registry’s command but not the other, breaking version sync. Always bump the version in package.json first, commit it, then run (or let CI run) both publish commands against that same commit.

Advanced tips for long-term maintainers

A few practices pay off once an extension has real users on both registries rather than just a handful of testers. Use vsce package --pre-release to maintain a separate pre-release channel so early adopters can opt into unstable builds without affecting your stable install base, a distinction both marketplaces surface separately in their UI. Pair your CI pipeline with an automated changelog and version-bump tool, so tagging a release also generates release notes from your commit history instead of relying on a maintainer to write them by hand every time.

If your extension bundles native binaries, register platform-specific builds using vsce’s target flags so Windows, macOS, and Linux users each download only the binary relevant to their platform rather than a bloated universal package. And because the VS Code Marketplace surfaces install counts and star ratings while Open VSX tracks downloads without a star-rating system, track both dashboards separately if you’re trying to gauge how much of your adoption is coming from Cursor and other Open VSX-sourced editors specifically versus mainstream VS Code.

Finally, budget time for periodic manual audits of your own listings on both sites. Automated pipelines are good at catching version drift, but they won’t notice a rendering glitch in your README, a stale screenshot, or a description that no longer matches what the extension actually does after six months of feature additions. Set a recurring reminder, quarterly is reasonable for most projects, to open both listings side by side and read them as a new user would.

Complete working project: a dual-publish extension template

Putting everything together, here’s the full file layout for a minimal extension set up to publish cleanly to both registries from day one.

my-extension/
├── .github/
│   └── workflows/
│       └── publish.yml
├── src/
│   └── extension.ts
├── out/                  (generated by npm run compile)
├── icon.png
├── package.json
├── tsconfig.json
├── .vscodeignore
├── .gitignore
├── README.md
├── CHANGELOG.md
└── LICENSE

src/extension.ts holds your real logic, starting from whatever the Yeoman generator scaffolded in Step 1. package.json follows the structure from Step 2, with license, repository, and icon all filled in. .vscodeignore excludes source and build tooling from the packaged .vsix as shown in Step 6. .github/workflows/publish.yml is the pipeline from Step 11, reading VSCE_PAT and OVSX_PAT from repository secrets. With that layout in place, the entire release process is: bump the version, commit, tag, push the tag, and both marketplaces update from the same build within minutes for the VS Code Marketplace and up to a couple of hours for Open VSX to finish propagating to Cursor’s search index.

Frequently asked questions

Does Cursor ever pull directly from the VS Code Marketplace instead of Open VSX?
No. Cursor’s Extensions panel sources third-party extensions from Open VSX through its own marketplace.cursorapi.com proxy, not from Microsoft’s Marketplace, so publishing to the VS Code Marketplace alone won’t make your extension discoverable inside Cursor.

Is publishing to Open VSX free?
Yes, for both open-source and commercial extensions. There’s no listing fee or revenue share on either registry for the publishing workflow covered in this guide.

Can I get my extension working in Cursor without publishing it anywhere?
Yes. Package it into a .vsix with vsce package and have users install it through Cursor’s “Install from VSIX” command. This works for private, internal, or in-development extensions that don’t need public discoverability.

My extension is already on the VS Code Marketplace but not Open VSX. Can Cursor users still get it?
Only by manually downloading the .vsix from the Marketplace website and sideloading it into Cursor. It won’t show up in Cursor’s Extensions panel search until you publish it to Open VSX directly.

Does @vscode/vsce also publish to Open VSX?
No. vsce only handles the VS Code Marketplace. Open VSX requires the separate ovsx CLI, which is why this guide covers both tools rather than treating one as a superset of the other.

How long does Open VSX’s review take?
Typically a few minutes for a straightforward extension. It can take longer if the automated secret-detection, blocklist, or namespace similarity checks flag something that needs manual review or a change on your end.

Do I need separate descriptions, icons, or screenshots for each marketplace?
No. Both registries read from the same packaged .vsix and the same package.json manifest, so one set of assets and metadata serves both listings.

What if my preferred publisher ID is already taken on one registry but not the other?
Namespaces on Open VSX and publisher IDs on the VS Code Marketplace are tracked independently, so this can happen. Pick your name on whichever registry you register with first, then try to secure the identical name on the second before you publish anywhere, to avoid ending up with two different-looking identities for the same extension.

Related Coverage

Nadia Dubois

Nadia Dubois

AI & Innovation Editor

Nadia Dubois is the AI & Innovation Editor at Tech Insider, where she tracks the rapid evolution of artificial intelligence, from foundation models to real-world enterprise deployment. She previously covered AI and startups for La Tribune and contributed to MIT Technology Review's European coverage. Nadia specializes in generative AI, AI regulation, and the intersection of technology and European industrial policy. She holds a dual degree in Computational Linguistics and Journalism from Sciences Po Paris.

View all articles