# Posts

First published: Jan 14, 2017, 6:47pm MST
Last edited: May 4, 2018, 12:46pm MDT

## Magic GOPATH

Maybe someday I’ll start writing about things besides Go again.

Go requires that you set an environment variable for your workspace called your GOPATH. The GOPATH is one of the most confusing aspects of Go to newcomers and even relatively seasoned developers alike. It’s not immediately clear what would be better, but finding a good GOPATH value has implications for your source code repository layout, how many separate projects you have on your computer, how default project installation instructions work (via go get), and even how you interoperate with other projects and libraries.

It’s taken until Go 1.8 to decide to set a default and that small change was one of the most talked about code reviews for the 1.8 release cycle.

After writing about GOPATH himself, Dave Cheney asked me to write a blog post about what I do.

## My proposal

I set my GOPATH to always be the current working directory, unless a parent directory is clearly the GOPATH.

Here’s the relevant part of my .bashrc:

# bash command to output calculated GOPATH.
calc_gopath() {
local dir="$PWD" # we're going to walk up from the current directory to the root while true; do # if there's a '.gopath' file, use its contents as the GOPATH relative to # the directory containing it. if [ -f "$dir/.gopath" ]; then
( cd "$dir"; # allow us to squash this behavior for cases we want to use vgo if [ "$(cat .gopath)" != "" ]; then
cd "$(cat .gopath)"; echo "$PWD";
fi; )
return
fi

# if there's a 'src' directory, the parent of that directory is now the
# GOPATH
if [ -d "$dir/src" ]; then echo "$dir"
return
fi

# we can't go further, so bail. we'll make the original PWD the GOPATH.
if [ "$dir" == "/" ]; then echo "$PWD"
return
fi

# now we'll consider the parent directory
dir="$(dirname "$dir")"
done
}

my_prompt_command() {
export GOPATH="$(calc_gopath)" # you can have other neat things in here. I also set my PS1 based on git # state } case "$TERM" in
xterm*|rxvt*)
# Bash provides an environment variable called PROMPT_COMMAND. The contents
# of this variable are executed as a regular Bash command just before Bash
# displays a prompt. Let's only set it if we're in some kind of graphical
# terminal I guess.
PROMPT_COMMAND=my_prompt_command
;;
*)
;;
esac


The benefits are fantastic. If you want to quickly go get something and not have it clutter up your workspace, you can do something like:

cd \$(mktemp -d) && go get github.com/the/thing


On the other hand, if you’re jumping between multiple projects (whether or not they have the full workspace checked in or are just library packages), the GOPATH is set accurately.

More flexibly, if you have a tree where some parent directory is outside of the GOPATH but you want to set the GOPATH anyways, you can create a .gopath file and it will automatically set your GOPATH correctly any time your shell is inside that directory.

The whole thing is super nice. I kinda can’t imagine doing something else anymore.

Update: vgo is the future, and works better without a GOPATH set in some cases. I’ve updated the script to allow you to squash the behavior by making an empty .gopath file.