DEV Community

Cover image for What are go workspaces and how do I use them?
Matt Boyle for Golang

Posted on • Updated on

What are go workspaces and how do I use them?

I previously blogged about generics being added as part of the Go 1.18 release. There was another quality of life improvement that was added with this release called "Go workspaces".

This is what the release notes said about workspaces:
workspace documentation from release notes, https://tip.golang.org/doc/go1.18

In this blog post, we are going to explore what Go workspaces are and how to use them.

If you like this blog post and want to support me to write more whilst learning more about Go, you can check out my book titled "Domain-driven design with Golang". You can get it from Amazon: [UK link], [US link].

go mod replace

Have you ever wanted to make a change to one of the Go modules your code depends on? After some googling you might have found yourself doing something similar to the below:

module test1.18

go 1.18

require golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect

replace golang.org/x/sync => ./local/sync
Enter fullscreen mode Exit fullscreen mode

This should be all we need. To test it I copied the code from golang.org/x/sync to ./local/sync. My file tree looks like this:
File tree
and then made a small edit to the Go func of errgroup:
Log line added to Go func or errgroup

and wrote a simple main func:
Simple main func calling eg.Go

As expected, when I run my program I get the following output:

2022/03/21 07:58:10 Let's go!
2022/03/21 07:58:10 did a thing
Enter fullscreen mode Exit fullscreen mode

Great, everything works!

Before go 1.18, this was pretty much the only way to make changes to multiple modules at once. You would then need to remember to remove your changes from go.mod before you commit your code.

Introducing Workspaces

With workspaces, this whole process becomes much easier. We can make a go.work file that effectively works the same as the replace directive we used previously. Let's follow the same example again but this time use a workspace file.

My go.mod file is reverted to be as follows:

module test1.18

go 1.18

require golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
Enter fullscreen mode Exit fullscreen mode

I then make a new file called go.work at the root of my project and added the following:

go 1.18

use ./local/sync
Enter fullscreen mode Exit fullscreen mode

That's truly it! The go tool detects the workspace file automatically and uses it. When I run go run ./workspace/main.go I get the same output as before:

2022/03/21 08:03:43 Let's go!
2022/03/21 08:03:43 did a thing
Enter fullscreen mode Exit fullscreen mode

In the Go 1.18 Beta you were able to run:

 go build -workfile=off ./workspace/main.go
Enter fullscreen mode Exit fullscreen mode

to build the code without using the workfile, but this didn't work for me with the production release. I raised a bug against the go tool here and it looks like it was removed before release which is a shame.

The correct way to do is now to run the following command:

GOWORK=off go run ./workspace/main.go
Enter fullscreen mode Exit fullscreen mode

and with this we get the following output:

2022/03/21 08:27:03 did a thing
Enter fullscreen mode Exit fullscreen mode

This shows it is now building with the original module in our go.mod file.

Best practises and Warnings

Early posts from the community are suggesting that not committing your go.work file is preferable. This makes sense, it is used for local development and after you have made and tested your changes to a module, you should push it, tag it and then reference it in your go.mod file as usual. Therefore, sharing go.work files doesn't make sense.

Consider adding go.work to your .gitignore.

A Warning though, if you do happen to push your go.work file it looks like if you run go build it will use your go.work file by default unless you explicitly turn it off. This could lead to production builds having development code in unintentionally. It therefore might be worth always running production builds with GOWORK=off go build ./... to be on the safe side.

Wrap up

I hope you find this useful. For more go tidbits, you can find me over on twitter here

Top comments (6)

Collapse
 
davidpfarrell profile image
David Farrell

Thanks for getting us up to speed on the new Go workspace feature.

Question:

Its called "Go workspaceS" but the feature appears to only support a single "go.work" file (ie a single workspace) ... Is it possible to configure and use, say "go2.work" (or something similar) and point to it?

Collapse
 
fiurthorn profile image
fiurþorn

you can place multiple rewrites in one file.

Collapse
 
fiurthorn profile image
fiurþorn • Edited

The workspace file should be in the parent directory of your project und the other module parallel to your project. So you don't need to change any thing in your project (.gitignore etc.). Go search on all parents for a go.work file.

Collapse
 
apav profile image
a-pav • Edited

I think this only worked for you because you've probably executed go mod edit -replace=<your-change> and go mod tidy commands before the creation of your go.work file.
There's an open issue about this at github.com/golang/go/issues/50750.
I think until that issue is resolved, using go.mod and its replace directive should remain the best way to go for importing an un-published/local version of a dependency.

Collapse
 
groggy7 profile image
Serhat Hakeri

Should i use go work file if my project is not multi module? If so, Why am i supposed to have go mod (and in some cases go sum) files under every single directory while i can make my project run perfectly fine with only one go mod and one go sum file in root directory (in case i dont have go work file. Its kinda visual pollution for me :)

Collapse
 
charlescirculo profile image
charles

I'm confused by workspaces, if I have multiple modules, but don't necessarily want to have them all on the same release schedule, is that possible in a workspace/monorepo?