What are go workspaces and how do I use them?
Tags: go, programming, softwaredevelopment
Published: 2022-03-21 08:46:21

I previously blogged about [generics] (https://dev.to/gophers/what-are-go-generics-when-should-i-use-them-39bg) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qeyve0g3xy0ihqtf2pqt.png)

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]](https://amzn.to/3uVEqBD), [[US link]](https://lnkd.in/e29nWWxZ).**

##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
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tr55pp9g93fahw3xrrkk.png)
and then made a small edit to the `Go` func of errgroup:
![Log line added to Go func or errgroup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8hqmemmvofxbwusvlahm.png)

and wrote a simple main func:
![Simple main func calling eg.Go](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ullj7l7kfz049tfbm2qz.png)

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
```

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
```

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
```

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
```

 In the Go 1.18 Beta you were able to run:
```
 go build -workfile=off ./workspace/main.go
```
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](https://github.com/golang/go/issues/51838) 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
```

and with this we get the following output:
```
2022/03/21 08:27:03 did a thing
```
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](https://twitter.com/mattjamesboyle)