How to set $GOPATH in dev shell

I’m working on my very first golang project on NixOS but I have some experience working with this programming language on Windows on the past. My problem now is that for some reason golangci-lint can’t analyze my code. It throws the following message in my code editor.

level=error msg="Running error: context loading failed: 
no golang files to analyze "running `go mod tidy` may solve the problem

Running go mod tidy doesn’t solve the problem unfortunately. Besides, I can’t use code for external files inside the same package. I did a bit of research on the internet and I got that $GOPATH is dealt in a different way when you work with dev-shells. I agree with that because I checked it with echo $GOPATH and got nothing.

I thought that my best bet was trying some solutions from this question. However none of them worked and to be honest I’m a bit confused with what’s going with my devshell.

let
  pkgs = import <nixpkgs> { };
in
pkgs.mkShellNoCC {
  packages = with pkgs; [
    gcc
    go
    golangci-lint
  ];
}

This is my languages.nix expression that install LSP server for me to be able to read code.

{ pkgs, ... }:
{
  home.packages = with pkgs; [
    lua-language-server
    nil
    nixfmt
    bash-language-server
    yaml-language-server
    yamlfmt
    nodePackages.vscode-json-languageserver
    ruff
    ty
    gopls
    golangci-lint-langserver
    delve
    ripgrep
    docker-language-server
    dockerfmt
  ];
}

I install gopls in my home manager to be able to open projects easily without setting up a shell for them if I don’t need doing that. For now I want to keep this shell simple because I don’t want to add more complexity as long as the projects needs me to.

I know that devshells basically install packages that are pointed to. How does it work in Go? I don’t want to install Go from my home manager to make available more globally but keep it small and in control, that’s what devshells are for, am I right?

How can I set GOPATH?

Why do you use a nocc shell and add GCC?

Also how do you run golint? Are you using a legacy or a go.mod project?

Go and it’s tooling doesn’t really support the legacy projects anymore as far as I understand.

So you really should use a proper go.mod. I don’t remember how to bootstrap those, but they shouldn’t rely on GOPATH much.

No that you mention it, I did something silly indeed, there’s no need for NoCC. That happened because I copied code from the devshell example. We’ll improve that now

I code with Helix editor (similar to neovim) and run language servers from a dedicated nix expression.

I’m using a go.mod project. I agree that I shouldn’t rely on GOPATH but again I’m new coding Go on NixOS so I’m a bit confused now

Thanks for taking time! I could set $GOPATH the way you did in home manager. echo $GOPATH outputs the right path but I still have the same two problems in my IDE. Now I haven’t set $GOMODCACHE yet, I’m gonna do that cause that makes sense for me.

Alright this is a bit weird, there shouldn’t be a problem with $GOPATH. I just printed it out from a test in go and I get this output:

go test src/component/component_template_test.go -run TestDescription -v

=== RUN   TestDescription
    component_template_test.go:17: Go path: /home/wavesinaroom/go
--- PASS: TestDescription (0.00s)
PASS
ok  	command-line-arguments	0.002s

This is my test:

func TestDescription(t *testing.T) {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		gopath = build.Default.GOPATH
	}
	t.Logf("Go path: %s", gopath)
}

Don’t put anything in home manager just use a shel to set up your environment. No need to set GOPATH.

This is what I use, I also use helix:

pkgs.mkShell {
    packages = with pkgs; [
      ## golang
      delve
      go-outline
      go
      golangci-lint
      golangci-lint-langserver
      gopkgs
      gopls
      gotools
    ];

    # Need to disable fortify hardening because GCC is not built with -oO,
    # which means that if CGO_ENABLED=1 (which it is by default) then the golang
    # debugger fails.
    # see https://github.com/NixOS/nixpkgs/pull/12895/files
    hardeningDisable = ["fortify"];
  }

Did you create a valid go.mod via go mod init after entering the shell?

1 Like

Hey! Thanks for taking time. I did create a module with go mod init.

@NobbZ, @StepBroBD and @eblechschmidt you guys have been awesome :slight_smile: Thanks for you answers!

At this point I think I’m doing something wrong in Go. This doesn’t seem to be a problem related to NixOS. I’m gonna make sure my project is right before continuing this thread if that’s alright with you.

i think you could try running go with envvars wrapepd like GOPATH=… GOMODCACHE=… go …

i’m setting those variables in home manager just be cause i have a couple go projects and i dont want a ~/go cluttering my sacred homedir

if you dont mind the trouble, adding those envvars in devshells individually would work the same (i think)

I tried that before but didn’t work. However, it is a good idea for keeping home tidy :slight_smile:

Yeah lads I must be doing something wrong with Go.

go.mod

module hello

go 1.25.5

hello.go

package main

import (
	"fmt"
	"hello/output"
)

func main() {
	o := output.GetOutput()
	fmt.Println(o)
}

output/output.go

package output

func GetOutput() string {
	return "output"
}

output/output_test.go

package output

import "testing"

func TestOutput(t *testing.T) {
	o := GetOutput()
	t.Log(o)
}

I quickly wrote this code that mimics my projects most basic structure. When I run go run . I get the expected output. However, when I run go test output/output_test.go -run TestOutput -v I get the undefined output I got before.

# command-line-arguments [command-line-arguments.test]
output/output_test.go:6:7: undefined: GetOutput
FAIL	command-line-arguments [build failed]
FAIL

What’s weird is that my previous projects I wrote on Windows follow that same structure. Now that was long ago, so I must be omitting something

Anyways, I’ll be searching on the internet for this so we don’t need to keep going replying to this question. This is definitely a problem not related to Nix

Sorry guys my bad :frowning:

I run go test command in the wrong way. A few weeks ago I worked intensely on a Python project and got myself confused with unit testing.

Have an awesome day!

No, please don’t do that. The whole point of Nix is not to have global tool chains but a dedicated shell.

you have your ways i go with mines :saluting_face:

Fair enough. Do what you want but don’t recommend it then as it is definitely not the the intended way. Especially as you are basically using a similar shell in your project: GitHub - stepbrobd/rfm: router flow monitor · GitHub

1 Like

Interesting thread. Thanks for sharing everyone.

Obviously, using LLMs that hallucinate it’s important to have a lot of linting, so here’s what I’ve been using recently. It found a surprising large amount of things.