- Setting Up Local Development Environment
- Creating VSIX Packages for the Extension
- Updating the
RoslynLanguage Server Version - Snapping for releases
Setting up your local development environment for the vscode-csharp repository involves several steps. This guide will walk you through the process.
Before you start, make sure you have the following software installed on your machine:
- Node.js v24 (24.13.0 LTS).
- Note - Building with higher major versions of Node.js is not advised - it may work but we do not test it.
- Npm (The version shipped with node is fine)
- .NET 10.0 SDK (dotnet should be on your path)
Once you have these installed, you can navigate to the cloned vscode-csharp repository to proceed with building, running, and testing the repository.
Follow these steps to build, run, and test the repository:
If you have the ability to run powershell, you can invoke "init.ps1" from the root of the repo. If not, the following steps will get build going for you as well:
- Run
npm ci- This command installs the project dependencies.
Note: Authentication with ado-npm-auth is only required when adding new packages to the feeds. For regular development with existing dependencies, authentication is not necessary. See the Updating NPM packages section for details.
You can now run code . - This command opens the project in Visual Studio Code.
After completing the build steps:
- Run
npm run watch(Optional) - This command watches for code changes. - Press Ctrl+Shift+D to open the Run view in VS Code and ensure
Launch Extensionis selected. - Start debugging by pressing F5.
To run all unit tests, execute npm run test:unit.
To run all integration tests execute npm run test:integration
To debug unit tests locally, press F5 in VS Code with the "Launch Tests" debug configuration selected.
To debug integration tests
- Import the
csharp-test-profile.code-profilein VSCode to setup a clean profile in which to run integration tests. This must be imported at least once to use the launch configurations (ensure the extensions are updated in the profile). - Open any integration test file and F5 launch with the correct launch configuration selected.
- For integration tests inside
test/lsptoolshost, use either[Roslyn] Run Current File Integration Testor[DevKit] Launch Current File Integration Tests(to run tests using C# + C# Dev Kit) - For integration tests inside
test/razor, use[Razor] Run Current File Integration Test - For integration tests inside
test/omnisharp, use one of the[O#] Run Current File Integration Testcurrent file profiles
- For integration tests inside
These will allow you to actually debug the test, but the 'Razor integration tests' configuration does not.
This section shows how to set up local Razor or Roslyn language servers for debugging with the VSCode C# extension.
- Clone the Roslyn repository. This repository contains the Roslyn server implementation.
- Follow the build instructions provided in the repository.
The server DLL is typically at $roslynRepoRoot/artifacts/bin/Microsoft.CodeAnalysis.LanguageServer/Debug/net9.0/Microsoft.CodeAnalysis.LanguageServer.dll, but this may vary based on the built configuration.
- Clone the Razor repository. This repository contains the Razor server implementation.
- Follow the build instructions provided in the repository.
The extension is typically at $razorRepoRoot/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension/Debug/net9.0.
Before running the language servers, familiarize yourself with the steps in the Configuring Local Language Servers section to configure either the Roslyn or Razor language servers for debugging .
Note: You would only need to configure this for the workspace you wish to debug, NOT for the repo root of vscode-csharp repo.
Follow these steps to enable debugging:
- Press
Ctrl+Shift+Dand thenF5to launch the extension. This will open a new VS Code instance forvscode-csharprepo. - In the new VS Code instance, open the project or solution you want to debug.
- Follow instructions in Configuring Local Language Servers to find and configure the workspace settings for the language server you want to debug.
- Ensure the language server is fully built in Debug mode.
- Meanwhile in a Visual Studio instance open the
.slnsolution file for the language server you want to debug. Keep this instance open for use in a later step. - Back on VS Code, press
Ctrl+Shift+Pand selectReload Window. This ensures the changes made in step 3 are applied. - After reloading, a window will pop up prompting you to select or open a Visual Studio instance. Now, select the instance you opened in step 5.
- The language server will now trigger a breakpoint on
Debugger.Launch()when it starts.
This section provides instructions on how to debug locally built Roslyn and Razor language servers. You can do this by either directly editing the settings.json file of your workspace or through the VSCode settings interface.
- Open the Command Palette with
Ctrl+Shift+P(orCmd+Shift+Pon macOS) - Type "Preferences: Open Workspace Settings"
- Select the option that appears.
- In the Workspace Settings tab, in the upper right corner, you'll see an icon that looks like a document with an arrow, which is the "Open Settings (JSON)" button.
- Click on this button to open the
settings.jsonfile.
Add the following lines to your settings.json. Replace <roslynRepoRoot> with the actual path to your Roslyn repository.
"dotnet.server.waitForDebugger": true,
"dotnet.server.path": "<roslynRepoRoot>/artifacts/bin/Microsoft.CodeAnalysis.LanguageServer/Debug/net9.0/Microsoft.CodeAnalysis.LanguageServer.dll"If using C# Dev Kit, you also need to override the Roslyn DevKit component in your settings.json. This step is not necessary if you are not loading the Dev Kit extension.
"dotnet.server.componentPaths": {
"roslynDevKit": "<roslynRepoRoot>/artifacts/bin/Microsoft.VisualStudio.LanguageServices.DevKit/Debug/net9.0"
},Or, in VSCode settings (Ctrl+,):
- Search for
dotnet server. - Set
dotnet.server.pathto the path of your Roslyn DLL. - Enable
dotnet.server.waitForDebugger. - (Optional) - add the component to
dotnet.server.componentPaths(see above).
Add the following lines to your settings.json. Replace <razorRepoRoot> with the actual path to your Razor repository.
"dotnet.server.componentPaths": {
"razorExtension": "<razorRepoRoot>/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension/Debug/net9.0"
},We use the .NET eng AzDo artifacts feed https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-public-npm/npm/registry/ with upstreams to the public npm registry.
Note: Authentication is only required when adding new packages to the feeds. For installing existing dependencies during regular development, authentication is not necessary.
To add new packages, you must authenticate by running:
npm install -g ado-npm-auth(if not already installed)ado-npm-auth -c .npmrc
To package this extension, we need to create VSIX Packages. The VSIX packages can be created using the command npm run vsix:release:package. This will create all the platform specific VSIXs that you can then install manually in VSCode.
In order to pull in new packages from upstreams into the msft_consumption feed we use for restoring, you will need to be a member of the 'CSharp VS Code Extension contributors' group in the Azure Devops instance.
To update the version of the roslyn server used by the extension do the following:
- Find the the Roslyn signed build you want from here. Typically the latest successful build of main is fine.
- In the official build stage, look for the
Publish Assetsstep. In there you will see it publishing theMicrosoft.CodeAnalysis.LanguageServer.neutralpackage with some version, e.g.4.6.0-3.23158.4. Take note of that version number. - In the package.json inside the
defaultssection update theroslynkey to point to the version number you found above in step 2. - Ensure that version of the package is in the proper feeds by running
npm run updateRoslynVersion. Note: you may need to install the Azure Artifacts NuGet Credential Provider to run interactive authentication. - Build and test the change. If everything looks good, submit a PR.
In order to pull in the latest version of Roslyn Copilot bits from the VS Conversations repo, follow these steps:
- Trigger this pipeline which should automatically publish bits to the storage account and then create an insertion PR like this
- Build and test the change to ensure the roslyn copilot language server bits are downloaded correctly. You'll see log entries like the below in the Output->C# pane:
[info] Installing package 'Language server for Roslyn Copilot integration'
[info] Finished
More details for this are [here] (https://devdiv.visualstudio.com/DevDiv/_git/VisualStudio.Conversations?path=/src/Copilot.Roslyn.LanguageServer/README.md)
Extension releases on the marketplace are done from the prerelease and release branches (corresponding to the prerelease or release version of the extension). Code flows from main -> prerelease -> release. Every week we snap main -> prerelease. Monthly, we snap prerelease -> release.
The extension follows a specific versioning scheme for releases:
- Prerelease versions: Use standard minor version increments (e.g., 2.74, 2.75, 2.76...)
- Stable release versions: Use the next tens version (e.g., 2.74 prerelease becomes 2.80 stable)
- Main branch after RC snap: Jumps to one above the next stable version (e.g., if snapping 2.74 as RC, main becomes 2.81)
The snap is done via the "Branch snap" github action. To run the snap from main -> prerelease, run the action via "Run workflow" and choose main as the base branch.

When running the snap action, you can optionally check the "Is this a release candidate snap" checkbox. If checked:
- The prerelease branch will receive the snapped code with the current version (e.g., 2.74)
- The main branch version will be updated to be higher than the next stable release (e.g., 2.81, since the next stable would be 2.80)
This will generate two PRs that must be merged. One merging the main branch into prerelease, and the other bumps the version in main.

To snap from prerelease to release, run the same action but use prerelease as the workflow branch. This will generate a PR merging from prerelease to release, and automatically update the version to the next stable release version (e.g., 2.74 -> 2.80) on the merge branch before the PR is merged.
The marketplace release is managed by an internal AzDo pipeline. On the pipeline page, hit run pipeline. This will bring up the pipeline parameters to fill out:
- The branch will always be main, no matter if release a build from prerelease or release.
- Uncheck the "test" option.
- In "Resources", choose "dotnet-vscode-csharp [officialBuildCI]", then check only the build that should be released, and then confirm with "Use selected run". Based on the selected build, it will automatically determine if it is prerelease or release.

- The pipeline parameters should then look something like the following image. Hit "Run".

- After a bit, the pipeline will request approval from an authorized approver before it actually uploads to the marketplace. Hit approve and it will continue.