← Back to blog

Running Isolated VS Code Instances

This setup runs two independent VS Code instances: one for UR-COMPANY and one for client work. Each instance has its own settings, profiles, sign-in state, extensions, and window state.

You need the VS Code code CLI available on PATH. Check that first:

Terminal
command -v code
code --version

If command -v code returns nothing, install the CLI using your editor's documented shell-command installation method, then open a new terminal. In VS Code on macOS, use Shell Command: Install 'code' command in PATH from the Command Palette.

What this setup isolates

--user-data-dir separates settings, profiles, authentication state, and window state. --extensions-dir separates installed extensions. Both flags are required on every launch; omitting either one reintroduces shared state.

This does not isolate operating-system resources. Git configuration, SSH keys, credential stores, environment variables, and other credentials remain shared unless you configure them separately.

1. Create the directories

Run this once in a terminal. The environment variables are used by the later commands in this article.

Terminal
export COMPANY_VSCODE="$HOME/vscode-ur-company"
export CLIENT_VSCODE="$HOME/vscode-client"

mkdir -p "$COMPANY_VSCODE/data" "$COMPANY_VSCODE/extensions"
mkdir -p "$CLIENT_VSCODE/data" "$CLIENT_VSCODE/extensions"

2. Launch each instance

Run one command per instance. In each new window, sign in with the account for that context.

Terminal
# UR-COMPANY (company)
code --user-data-dir "$COMPANY_VSCODE/data" \
	--extensions-dir "$COMPANY_VSCODE/extensions"

# CLIENT
code --user-data-dir "$CLIENT_VSCODE/data" \
	--extensions-dir "$CLIENT_VSCODE/extensions"

3. Add convenient shell aliases

Append this block to ~/.profile. bash and many other Unix shells read this file for login sessions. If your shell uses another startup file, put the same block there.

~/.profile
export COMPANY_VSCODE="$HOME/vscode-ur-company"
export CLIENT_VSCODE="$HOME/vscode-client"

alias ur-company-code='code --user-data-dir "$COMPANY_VSCODE/data" --extensions-dir "$COMPANY_VSCODE/extensions"'
alias client-code='code --user-data-dir "$CLIENT_VSCODE/data" --extensions-dir "$CLIENT_VSCODE/extensions"'

Reload it with . ~/.profile. Use ur-company-code and client-code instead of calling code directly.

4. Make the active context visible

A title prefix provides a useful confirmation before you start editing. Add this to the UR-COMPANY instance's ~/vscode-ur-company/data/User/settings.json:

settings.json
{
  "git.autofetch": true,
  "workbench.colorTheme": "Default Dark Modern",
	"window.title": "[UR-COMPANY] ${activeEditorShort}${separator}${rootName}"
}

Use [Client] in the client instance. The title prefix is the useful part; a different theme is optional.

5. Move extensions into the new instances

Export extension IDs from the existing default instance, then install them into each isolated instance. Reinstalling lets VS Code select packages for the current OS and CPU architecture.

Original VS Code setup
code --list-extensions > "$HOME/vscode-extensions.txt"

Run this while the original/default instance is the one being inventoried. If it already uses custom directories, add the same --user-data-dir and --extensions-dir flags to the command.

Client instance
while IFS= read -r extension; do
  [ -z "$extension" ] || code \
    --user-data-dir "$HOME/vscode-client/data" \
    --extensions-dir "$HOME/vscode-client/extensions" \
    --install-extension "$extension"
done < "$HOME/vscode-extensions.txt"

Repeat the installation command with $COMPANY_VSCODE in place of $CLIENT_VSCODE. The export contains extension IDs only. Do not use --show-versions output as install input unless you intentionally pin versions.

Private extensions, local VSIX packages, and discontinued or platform-specific extensions may need separate handling. Sharing one extension directory is possible, but it weakens isolation because both instances can update or remove the same files; separate directories remain the more predictable default.

Verify the result

  • Launch both instances with unique user-data and extension directories.
  • List extensions with each instance's flags and confirm the expected inventories.
  • Change a harmless setting or theme in one instance and confirm it does not appear in the other.
  • Sign into the intended account in each instance and test the extensions that matter for that workflow.
  • Confirm the executable launchers use the same paths as the terminal aliases.

macOS: add an Automator application

This step is macOS-specific and optional. Open Automator, choose Application, add a Run Shell Script action, select /bin/zsh, and paste the launcher command below. Replace /path/to/code with the path from command -v code. Save it as Client VS Code.app, then repeat with the UR-COMPANY paths.

Automator · Run Shell Script
#!/bin/zsh
exec /path/to/code --user-data-dir "$HOME/vscode-client/data" \
	--extensions-dir "$HOME/vscode-client/extensions"

Test the application from Finder or Spotlight. Give the two applications distinct names so the active account is visible before a project opens.

After this, always open a project with one of the two aliases or launchers. Git credentials and SSH keys are still shared at the operating-system level; isolate those separately if the two accounts must never overlap.