VSCode extensions setup

As far as I can tell, one cannot easily use cpptools in visual studio code, due the C# executable. Thus, developing C/C++ is not really possible with VSCode on NixOS.

To work around this, we can use vscode-with-extension and use an overlay to install cpptools via nix:

self: super:
    mycode = super.vscode-with-extensions.override {
        # When the extension is already available in the default extensions set.
        vscodeExtensions = with super.vscode-extensions; [

However, this removes all existing plugins, from VSCode and prevents you from installing them via VSCode Marketplace.
We can also work around this, by declaring every extension in our above setup.
This is where the problem arises, in my opinion, for every unpackaged extension, I have to declare it, include the commit and if I want to update I need to modify the commit hash.
It seems unfeasible for me to update manually the commit hash of each package that I want to update.

Are my observations correct?
Could I automate the updating of plugins?
Can I install cpptools without declaring it explicitly in a vscode-with-extensions?


Good you’ve mentioned you are using NixOS (because my method won’t work with plain Nix)

My recipe for this is to install extensions imperatively. In those rare cases when it is not possible (cpptools requires some native libs, lucky it is packaged in Nixpkgs), use this module:


{ config, pkgs, lib, ... }: {
    options = {
        vscode.extensions = lib.mkOption { default = []; };
        vscode.user = lib.mkOption { };     # <- Must be supplied
        vscode.homeDir = lib.mkOption { };  # <- Must be supplied
        nixpkgs.latestPackages = lib.mkOption { default = []; };

    config = {
        # DIRTY HACK
        # This will fetch latest packages on each rebuild, whatever channel you are at
        nixpkgs.overlays = [
            (self: super:
                let latestPkgs = import (fetchTarball https://github.com/nixos/nixpkgs-channels/archive/nixpkgs-unstable.tar.gz) {
                        config.allowUnfree = true;
                in lib.genAttrs config.nixpkgs.latestPackages (pkg: latestPkgs."${pkg}")
        # END DIRTY HACK

        environment.systemPackages = [ pkgs.vscode ];

        system.activationScripts.fix-vscode-extensions = {
            text = ''
                mkdir -p $EXT_DIR
                chown ${config.vscode.user}:users $EXT_DIR
                for x in ${lib.concatMapStringsSep " " toString config.vscode.extensions}; do
                    ln -sf $x/share/vscode/extensions/* $EXT_DIR/
                chown -R ${config.vscode.user}:users $EXT_DIR
            deps = [];

Then in configuration.nix you add lines:

  imports = [
  vscode.user = "danbst";
  vscode.homeDir = "/home/danbst";
  vscode.extensions = with pkgs.vscode-extensions; [
  nixpkgs.latestPackages = [

And rebuild. What it does:

  • fetches latest nixpkgs-unstable channel on each rebuild
  • uses vscode and extensions from that channel, so up-to-date ASAP
  • links cpptools directly into ~/.vscode/extensions, which fools VScode to think it actually installed this ext

This is really cool, including the dirty hack.
I honestly feel like this should be documented somewhere, I was not able to find such a great how to!

Is it also possible to get the same result with only user overlays?

“Dirty hack” will never become “official”. For example, I’ve had to revert the abovementioned “fetch latest VScode” hack from my configuration. Why? It crashed sometimes, probably due to essential impurities: glibc mismatch, protocols mismatch, kernel mismatch, whatnot. I think, it crashed only because of this update, not because VSCode has an actual bug.

Another example is calibre - latest calibre crashes for me on opening file, but I suppose it crashes only for me. And will no longer crash after system update.

It is also nightmare to debug such cases, so better to stick to packages coherent with system.

Then the problem persists, how can I install packages over nix, while also maintaining the “ease of use” of querying for packages in the editor and installing them?

Oh, no. latest Nix package and VScode extensions live in different worlds. You still can use second part of my solution above. Just remove nixpkgs.latestPackages part from configuration.

Yes, you’ll have slightly outdated VSCode. But maybe better to switch to nixos-unstable channel and update your system periodically (nixos-rebuild switch --upgrade or nixos-rebuild boot --upgrade && reboot)? This would solve your other issue as well.

You might want to add your voice to Microsoft/vscode/issues/27972: Include support for system-wide mandatory/default settings which would allow us to trivially have both nix provided extensions (system wide) and user extensions (managed by vscode).

In the meantime, one might be tempted to write a companion helper to vscode-with-extensions which instead of passing the --extension-dir argument in its wrapper, dynamically creates symlinks to each nix provided extension before launching vscode.