Disclosure: I worked through this with an AI assistant. The behavioural findings below are things I actually tested on my machine and confirmed.
Setup
Several repos, each with a flake default devShell providing VSCodium (via vscode-with-extensions) with project-specific extensions. Goal: entering a project’s shell gives an editor with exactly that project’s extensions, reproducibly, while developer-level user settings (font size, theme, keybindings) stay shared across all projects and are owned by home-manager.
Problem
Open VSCodium from project A, then project B while A is open → B’s window shows A’s extensions. Only the first-opened project’s extension set applies to every window.
Cause (assistant’s analysis, unverified by me)
A VSCodium “instance” is keyed on --user-data-dir, not --extensions-dir. The second launch finds the first instance’s IPC socket and delegates “open folder” to it instead of starting a new main process, so its --extensions-dir is ignored and it inherits the first instance’s extension host. Forcing a distinct --user-data-dir per project makes them separate instances.
Solution that worked for me
A personal wrapper (lives on the flake side, since a devShell is evaluated by the project flake — home-manager can’t inject into it). It gives each project its own data dir but symlinks the human-authored config from home-manager’s real VSCodium user dir so settings stay shared:
codiumWrapped = pkgs.writeShellScriptBin "codium" ''
set -euo pipefail
# per-project data dir -> separate instance -> its own extensions
data_dir="$PWD/.vscodium/user-data"
mkdir -p "$data_dir/User"
# home-manager's ACTUAL VSCodium user dir (Linux; macOS differs)
shared="''${XDG_CONFIG_HOME:-$HOME/.config}/VSCodium/User"
# share only human-authored, read-at-startup config
# (NOT globalStorage/state.vscdb -> avoids concurrent SQLite writes)
for f in settings.json keybindings.json snippets; do
[ -e "$shared/$f" ] && ln -sfn "$shared/$f" "$data_dir/User/$f"
done
exec ${codium}/bin/codium --user-data-dir "$data_dir" "$@"
'';
(Add .vscodium/ to .gitignore.)
What I actually tested
- Extension isolation: works
- Shared settings: works, but after a change wrapped instances need Reload Window (Ctrl/Cmd+R) after
home-manager switch; the global instance updates live - Workspace Trust: isolated. It lives in per-project
globalStorage/state.vscdb, which I keep per-instance on purpose. I was not willing to disable Restricted Mode (security.workspace.trust.enabled = false), so I accept a one-time trust prompt per project; because the state dir is per-project-persistent, it only prompts once per repo.
Open question
Is there a more idiomatic pattern for this than a personal symlink wrapper? Anything upstream in nix-vscode-extensions / programs.vscode that already addresses multi-instance + shared settings?
Thanks!