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.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
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.
| Factor | VS Code Marketplace | Open VSX |
|---|---|---|
| Operated by | Microsoft | Eclipse Foundation |
| CLI tool | @vscode/vsce | ovsx |
| Account needed | Azure DevOps organization | Eclipse Foundation account linked to GitHub |
| Auth method | Personal Access Token (PAT), migrating to Entra ID workload identity federation before Dec. 1, 2026 | Access token generated on open-vsx.org |
| Identity unit | Publisher ID | Namespace |
| Automated review | Marketplace content policy checks | Secret detection, blocklist screening, namespace similarity analysis |
| Consumed by | VS Code (default) | Cursor, VSCodium, Gitpod, Eclipse Theia, and other Code OSS forks |
| Cost to publish | Free | Free |
| Popularity signal | Install count and star ratings | Download 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 account | Version / requirement | What it’s for |
|---|---|---|
| Node.js | 20.x LTS or newer | Runs vsce and ovsx via npm/npx |
| Visual Studio Code | 1.138 (stable, released Aug. 26, 2026) or newer | Local development and the Extension Development Host |
| Cursor | 3.21.16 (released Sept. 19, 2026) or newer | Verifying your extension loads and searches correctly |
| @vscode/vsce | Latest version via npm | Packages and publishes to the VS Code Marketplace |
| ovsx CLI | Latest version via npx | Publishes the same package to Open VSX |
| Yeoman + generator-code | Latest via npm | Scaffolds the starter extension project |
| Azure DevOps organization | Free tier | Required to generate a Marketplace Personal Access Token |
| Eclipse Foundation account | Free | Required to publish to Open VSX |
| GitHub account and repo | Free | Hosts 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
publisherfield inpackage.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-idand 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
ovsxCLI 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
licensefield inpackage.jsonas 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 wrongmainpath 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
publisherfield inpackage.jsonso 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-namespacecommand, 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
iconpath inpackage.jsonmust 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.jsonfirst, 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.





