DEV Community

Cover image for GoLang without a PATH (Intro to Go Modules)

Posted on • Updated on

GoLang without a PATH (Intro to Go Modules)

Unshackle thyself from thy GO_PATH, with go modules

We received the gift of Go Modules, with Go 1.11. Go modules are great for several reasons, but My FAVORITE reason is the fact that it allows you to run your Go code OUTSIDE OF YOUR GOPATH. Let’s talk about how to use them.

From scratch

To start a new project as a Go Module: Create the project directory, write a simple main.go (you can find some simple examples on gobyexample), and then run

$ go mod init <project-name>

Now you’ll have a go.mod file. If you’re familiar with npm, I essentially think of this as your package.json when you are using npm. This is where all of the imports that your module needs, are specified. It’ll be initialized with your new module being declared at the top of it. Now run the following command, inside of your new module.

$ go build

Now, it’ll actually work without being in your GO_PATH. It will also pull in all of the required modules and list them in your go.mod file. It will use the most up to date version of the package if not otherwise specified. Also, you’ll actually see output from the build process, rather than just having the executable. If you view the mod file, you’ll see that it also lists out indirect dependencies that your module is using. Running go build will also create a go.sum file, which we’ll talk more about in the next section. Another very important command to remember is

$ go mod tidy

When you run go build, it does not apply the dependencies that your tests are using to your go.mod and go.sum files. Running go mod tidy will make sure that all dependencies, including the test dependencies, are accounted for.

Now your go.sum file contains your built dependency versions and their hashes. Again if you’re familiar with npm, you can imagine this to be something like your package-lock.json. You don’t necessarily have to commit your go.sum file, but I’d highly recommend that you do. The hashes make sure that if you are importing a module of version v1.2.3, that the specific release wasn’t tampered with. There could be a mess up on the maintainers/contributors side and some change was forcibly pushed into the exact same version, making that version corrupt. Your hashes will defend you from that.

Go.sum also essentially tracks the history of the packages that you’ve used. If you decided to use v1.2.2 after already having used v1.2.3, go.sum will add the version hash of v1.2.2 and still maintain the hash of v1.2.3. This is done so that if you decide that you want to bump back to the higher version, you will be able to continue using the same package that you previously depended on.

NOTE: If others need/want to use your module in their projects, it will just work for them if they are using Go 1.11 or later. Some previous versions MAY also work without any issues. If you want to make sure that it WILL work on older versions, you must vendor your dependencies. All of your dependencies that you are using should be stored locally in your GO_PATH under something resembling /go/pkg/mod/. To assure that all of those dependencies are installed for others depending on your module, run the following command

$ go mod vendor

inside of your module. now you’ll see that you have a vendor file in your module.

From an existing project that isn’t using modules or go deps

Sooo now you’re wondering how you’d migrate one of your existing Go projects into a module. Run go mod init on your existing project, and now it is pretty much a module but not yet finished. There is just a little tidying to do. Next, run go get ./… and it will assemble all of your projects dependencies into your mod file. Finally run go mod tidy to get all the rest of the dependencies in your project.

From existing project that is using go deps

Nooooow how to migrate from using go deps to just using modules? Running go mod init will use your Gopkg.lock to build your go.mod and go.sum files. Then run go mod tidy to also collect all of your test dependencies. You can then remove Gopkg.lock, Gopkg.toml, and your old vendor files from the project. Then run go get ./… and finally, as a sanity check, run go test ./… to make sure everything still works as expected.

And once again, you can run go mod vendor in both of these situations to continue supporting those running older versions of Go.

Visit me on Twitter <3

Discussion (2)

buphmin profile image

Yeah go modules just made more sense to me as I started to learn go. When I first started looking and I saw the gopath requirement I took a step back and went "wait, you want me to do what now". Fortunately I found go modules and all was well in the world.

dizveloper profile image
Edvin Author

Yeah totally. I loved writing Go, but my biggest gripe was the GoPath. It seemed like such a primitive limiter. Super happy about modules.