Last Updated: March 02, 2016
· nelsam

Separate GOPATH Per Go Project

As many Go developers likely know, the goimports tool is great for managing all of the imports in your file. It checks the signature of functions, variables, etc. that are called on undefined variables, then looks for any available imports in your $GOPATH with a matching signature, and updates your code with that import (and removes unused imports).

My problem is that I have several Go projects that are using similar syntax (they have some functions with equivalent signatures), and goimports sometimes chooses to import from the wrong repository. The solution was obvious: set up a separate $GOPATH for each project - that way, goimports would only load libraries in the $GOPATH of said project. Implementing that solution was ... less obvious. Here's my specific implementation:


First, I needed to add to my .zshrc so that every time my working directory changed, zsh would check for a $GOPATH in the working directory and all parent directories. I've restricted it to $HOME, so that it doesn't keep looking in parent directories all the way up to the root of the drive, but basically it just looks for any directories containing a file named .gopath - that's my way of signaling that the directory is a valid $GOPATH. Here is a gist containing the relevant chpwd function.


Second, I needed emacs (my editor of choice) to set up buffer-local variables for both $GOPATH and exec-path (emacs' version of $PATH) every time I open a Go file. It turns out emacs automatically looks for a file named .dir-locals.el in the directory of any files opened and all parent directories. This file can be set up to define certain variables based on the language of the file that's opened. Here is my implementation - I just symlink that file to $GOPATH/.dir-locals.el. Side note, that repository contains my full emacs config in the nelsam branch.

project init script

Third, I wrote a quick script to set up a new $GOPATH with the files needed for both zsh and emacs, run go get someProject, and install goimports, golint, and gocode. The syntax is:

go-get-project projectImportPath [destDir]


Overall, it seems to be working well. In each $GOPATH, I only work on the project that the $GOPATH is set up for, which also encourages me to write unit tests instead of relying on other projects to test functionality.

2 Responses
Add your response


You could usw autoenv to set the environments variables automatically when you enter your project directory in the shell. Together with autojump its a great combo for the shell.

over 1 year ago ·

That'd cover it, too. Personally, I prefer using zsh's chpwd() function in my .zshrc for this specific case, but autoenv looks like it would cover pretty much the same stuff.

over 1 year ago ·