In my quest to further develop my use of nix into my workflow, I came across an issue, how do I get the most recent version of Go into my home-manager flake. At the time of writing nixpkgs unstable only has Go 1.20.4, however as someone who writes Go full-time, I want the latest and greatest (1.20.5). The most used answer to this in Rust projects is overlays. Popular overlays like the oxalica overlay, are often used to get specific Rust versions. With this in mind, I started with the NixOS Wiki. This guide (and a little help from ChatGPT), helped to build the following into my config:
outputs = { nixpkgs, home-manager, ... }:
let
version = "1.20.5";
goverlay = final: prev: {
go = prev.go.overrideAttrs
(old: {
inherit version;
src = final.fetchFromGitHub {
owner = "golang";
repo = "go";
rev = "go${}";
sha256 = "sha256-H0XWXZr3YRNNnYVxC/v7Gatqm8ICKZpdUGe9xLqiDmA=";
};
});
};
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system; overlays = [ goverlay ];
};
in
This declaration is added to my flakeās output and uses Github to pull and compile the most recent version of Go while using the rest of the Nix package for compilation. Currently, this makes updates pretty slow as it recompiles Go at every change. In the future I would like to self-host (or use Cachix) to build a binary cache for Go versions. This would allow me to not compile this on my machine and instead download the binary from the cache.
UPDATE: 06/23/2023
Looking further, you can also skip the Github option entirely and use fetchurl to grab the source tar. This more closely matches what is being done by nixpkgs to begin with.
outputs = { nixpkgs, home-manager, ... }:
let
version = "1.20.5";
goverlay = final: prev: {
go = prev.go.overrideAttrs
(old: {
inherit version;
src = final.fetchurl
{
url = "https://go.dev/dl/go${}.src.tar.gz";
sha256 = "123ap6l3qambqra986yzd1zjdz3w5sv1aj1gcmwzxyicp8rw25cs";
};
});
};
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system; overlays = [ goverlay ];
};
in
One thing to note about doing overlays like this and overwriting packages is that it does it in place. However, if you wanted to pass this to home-manager as a different package source, you can do something like this:
outputs = { nixpkgs, home-manager, ... }:
let
version = "1.20.5";
goverlay = final: prev: {
go = prev.go.overrideAttrs
(old: {
inherit version;
src = final.fetchurl
{
url = "https://go.dev/dl/go${}.src.tar.gz";
sha256 = "123ap6l3qambqra986yzd1zjdz3w5sv1aj1gcmwzxyicp8rw25cs";
};
});
};
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
};
gopkgs = import nixpkgs {
inherit system; overlays = [ goverlay ];
};
in
{
homeConfigurations."user" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
# Specify your home configuration modules here, for example,
# the path to your home.nix.
modules = [ ./home.nix ];
extraSpecialArgs = { inherit gopkgs; };
# Optionally use extraSpecialArgs
# to pass through arguments to home.nix
};
};
I use this to allow for me to change my sources and NOT have it override the existing pkgs variable. This might be reverted in the future, but it was good practice in passing new variables to home-manager.