The extensions in my R profile, what they are for, and how I install them.
Modified
November 9, 2026
In VS Code, extensions belong to a profile: each profile has its own set. Settings Sync carries the lists between machines together with the rest of the profile (see Profiles and Settings Sync).
The tables below list the extensions in my R profile, which I use for all my R work. My teaching profile R-Lecturer has only vscode-R (reditorsupport.r, reditorsupport.r-syntax) and Quarto (quarto.quarto), plus Copilot Chat, which ships with VS Code (Profiles and Settings Sync).
What I would install for R
For R scripts, R packages and Quarto documents, I would start with these:
reditorsupport.r: the R extension (console, help, plots, workspace viewer).
reditorsupport.r-syntax: R syntax highlighting (installed together with the R extension).
rdebugger.r-debugger: the R debugger.
quarto.quarto: Quarto rendering, preview and editing.
The R side (R itself, radian and R packages such as languageserver, httpgd and vscDebugger) is covered in Installation.
My own extension: sets the R version for a workspace, from the versions rig manages or from renv.lock (R versions). Not on the Marketplace: installed from the .vsix of a GitHub release (how).
With Settings Sync on, VS Code installs each profile’s extensions when it downloads the profile on a new machine (see Profiles and Settings Sync).
Not on the Marketplace
Settings Sync and install_extensions.ps1 install extensions from the Marketplace, so neither can install the R Version Switcher. On each machine, download the .vsix from its latest release and run:
code --install-extension r-version-switcher-1.2.0.vsix--profile R
Manual rebuild
install_extensions.ps1 reads a list with one extension id per line and installs it into a named profile:
It checks that code (the VS Code command-line tool) is on PATH.
It skips blank lines, lines starting with #, and extensions the profile already has (code --list-extensions --profile <name>).
It installs the rest with code --install-extension <id> --profile <name>.
At the end it lists the failures and exits with code 1 if there were any.
The VS Code command line only installs into a profile that already exists; for a missing one it reports Profile '<name>' not found. The script then opens VS Code once with code --profile <name>, which creates an empty profile, waits until the profile is there, and continues. If that does not work, create the profile in the Profiles editor (File → Preferences → Profiles) and run the script again. Use -Profile Default for the Default profile.
Put the script and the lists in one folder, then run, for example:
Without -List, the script uses extensions-<Profile>.txt next to itself. It needs PowerShell 7 (pwsh).
Show the full file: install_extensions.ps1
#Requires -Version 7.0<#.SYNOPSIS Install the VS Code extensions from a list file into a VS Code profile..DESCRIPTION Reads a text file with one extension id per line (as written by `code --list-extensions`), and installs every id that the profile does not have yet. Blank lines and lines starting with "#" are ignored. Failures are listed at the end and the script then exits with code 1. The VS Code CLI installs extensions only into a profile that already exists: `code --profile <name> --install-extension <id>` stops with "Profile '<name>' not found." The only CLI way to create a profile is to open a window with it (`code --profile <name>`), which creates an empty one. So when the profile is missing, the script does that once, waits until the CLI can see the profile, and then installs. If that does not work, create the profile in the Profiles editor (File > Preferences > Profiles) and run the script again. Use -Profile Default for the Default profile..EXAMPLE pwsh -File install_extensions.ps1 Installs extensions-R.txt (next to the script) into the profile "R"..EXAMPLE pwsh -File install_extensions.ps1 -Profile R -List extensions-R.txt.EXAMPLE pwsh -File install_extensions.ps1 -Profile R-Lecturer Installs extensions-R-Lecturer.txt into the profile "R-Lecturer".#>[CmdletBinding()]param(# Name of the VS Code profile. "Profile" is an alias so that the# automatic variable $PROFILE is not overwritten.[Alias('Profile')][string]$ProfileName='R',# List of extension ids. Default: extensions-<Profile>.txt next to the# script.[string]$List,# Seconds to wait for a newly created profile to appear.[int]$CreateTimeout=60)$ErrorActionPreference='Stop'# --- Find the VS Code CLI ----------------------------------------------------$codeCmd=Get-Command code -CommandType Application -ErrorAction SilentlyContinue |Select-Object-First 1if(-not$codeCmd){Write-Error("The VS Code command 'code' is not on PATH. On Windows, tick 'Add to PATH' "+"in the installer; on macOS, run 'Shell Command: Install code command in PATH' "+"from the Command Palette. Then open a new terminal.")exit2}function Invoke-Code {# Runs the VS Code CLI and returns its exit code and output (stdout and# stderr as text), without letting stderr stop the script.param([string[]]$Arguments)$ErrorActionPreference='Continue'$PSNativeCommandUseErrorActionPreference=$false$output=&$codeCmd.Source @Arguments 2>&1|ForEach-Object{"$_"}[pscustomobject]@{ ExitCode =$LASTEXITCODE Output =@($output|Where-Object{$_-ne''})}}# --- Find the list -----------------------------------------------------------if(-not$List){$List=Join-Path$PSScriptRoot"extensions-$ProfileName.txt"}elseif(-not(Test-Path-LiteralPath $List)-and-not[System.IO.Path]::IsPathRooted($List)){# A relative path that is not in the current folder: try next to the script.$nextToScript=Join-Path$PSScriptRoot$Listif(Test-Path-LiteralPath $nextToScript){$List=$nextToScript}}if(-not(Test-Path-LiteralPath $List-PathType Leaf)){Write-Error"List not found: $List"exit2}$ids=Get-Content-LiteralPath $List-Encoding utf8 |ForEach-Object{$_.Trim()}|Where-Object{$_-and-not$_.StartsWith('#')}|Sort-Object-Uniqueif(-not$ids){Write-Warning"No extension ids in $List."exit0}# --- Make sure the profile exists ---------------------------------------------# The Default profile is used when --profile is not given.$profileArgs=if($ProfileName-eq'Default'){@()}else{@('--profile',$ProfileName)}function Get-InstalledExtensions {$r= Invoke-Code (@('--list-extensions')+$profileArgs)if($r.ExitCode-eq0){return,@($r.Output)}if($r.Output-match'not found'){return$null}# profile does not existthrow"code --list-extensions failed (exit $($r.ExitCode)): $($r.Output-join' ')"}$installed= Get-InstalledExtensionsif($null-eq$installed){Write-Host"Profile '$ProfileName' does not exist. Opening VS Code with it once to create it..."$null= Invoke-Code @('--new-window','--profile',$ProfileName)$deadline=(Get-Date).AddSeconds($CreateTimeout)while($null-eq$installed-and(Get-Date)-lt$deadline){Start-Sleep-Seconds 2$installed= Get-InstalledExtensions}if($null-eq$installed){Write-Error("Profile '$ProfileName' still does not exist. Create it in VS Code "+"(File > Preferences > Profiles > New Profile), then run this script again.")exit2}Write-Host"Profile '$ProfileName' created."}# --- Install -------------------------------------------------------------------Write-Host"Profile '$ProfileName': $($ids.Count) extension(s) in $(Split-Path$List-Leaf)."$done=[System.Collections.Generic.List[string]]::new()$skipped=[System.Collections.Generic.List[string]]::new()$failed=[System.Collections.Generic.List[string]]::new()foreach($idin$ids){# Extension ids are case-insensitive; -contains compares that way too.if($installed-contains$id){$skipped.Add($id)Write-Host" skip $id (already installed)"continue}$r= Invoke-Code (@('--install-extension',$id)+$profileArgs)$text=$r.Output-join' 'if($text-match'built-?in'){# E.g. GitHub Copilot Chat, which now ships with VS Code.$skipped.Add($id)Write-Host" skip $id (built into VS Code)"}elseif($r.ExitCode-ne0-or$text-match'Failed Installing|not found'){$failed.Add($id)Write-Host" FAILED $id : $text"-ForegroundColor Red}else{$done.Add($id)Write-Host" install $id"}}# --- Report ----------------------------------------------------------------------Write-Host''Write-Host"Installed: $($done.Count). Skipped: $($skipped.Count). Failed: $($failed.Count)."if($failed.Count-gt0){Write-Host'Failed extensions:'-ForegroundColor Red$failed|ForEach-Object{Write-Host" $_"-ForegroundColor Red }exit1}exit0