Go Work command: The functionality you must know

Nahuel Costamagna

Nahuel Costamagna

· 8 min read
Go Work command - Nahuel Costamagna

Introduction

Welcome to this post, where we'll discuss the Work command in Go, which was released in Go version 1.18.

In my case, my Go version is 1.21; however, you can use whatever latest version of 1.18

If we must make changes to a package that we are using in our project, with this functionality, we can use our local package, test it in our project without the necessity of uploading it to a repository, and import it. And without the necessity of using 'replace' in our go.mod file either.

Go Work

With this command, we can work with our locally imported package in our project instead of uploading our changes to our repository and then importing them into our project.

Go Work Init

With this command:

$ go work init

We created our go.work, which contains our local modules.

Go Work Use

With the use command, we can define the local modules imported into our project. For example, we can import our project into the go.work file.

$ go work use .

Our go.work file will look like

go 1.21.0

use (
	.
)

And we can add new modules (which are imported into our project)

$ go work use .../my-package

Our go.work file will look like

go 1.21.0

use (
	.
  ../my-package
)

In this way, we are going to use our local my-package package instead of the remote package.

Example

External package

We have the following package called domain, wherein we have a user struct with its tags.

package domain

type User struct {
	ID        string `json:"id"`
	FirstName string `json:"first_name"`
}

The repository of this package is blog_go_work_pkg , the latest tag is v0.0.1, and its folder structure is:


blog_go_work_pkg/
  ├─ domain/
  │    └─ user.go
  └─ go.mod

Project

We are going to create our project (in my case, I called it 'blog_go_work_project'). The first thing that we are going to do is initialize our go.mod file

go mod init

and import our external package

go get github.com/beeblogit/blog_go_work_pkg

we create our main.go file, import our package and use our User struct

We instantiate a user variable and perform 'Marshal' to display the user entity in JSON.

package main

import (
    "encoding/json"
    "fmt"
    "github.com/beeblogit/blog_go_work_pkg/domain"
)

func main() {
    u := domain.User{
      ID:        "1231",
      FirstName: "Nahuel",
    }

    value, _ := json.Marshal(u)
    fmt.Println(string(value))
}

and the result is

{"id":"1231","first_name":"Nahuel"}

But how can we perform changes in our package and import it without the need to upload the changes to the repository? In this way, we can use the 'work' functionality to perform this action.

Work functionality

As a clarification, it is necessary to have our Go path configuration set correctly and to respect our project structure.

my folder project struct from the GOPATH is


src/
  └─ github/
       └─ beeblogit/
            ├─ ...
            ├─ blog_go_work_pkg/
            ├─ blog_go_work_project/
            └─ ...

We are going to make some changes to our package, adding the 'LastName' and 'Country' fields (without uploading it to the repository).

type User struct {
    ID        string `json:"id"`
    FirstName string `json:"first_name"`
    LastName  string `json:"last_name"`
    Country   string `json:"country"`
}

In our project, we are going to execute the following command to create our go.work file

go work init .

A go.work file should have been generated with this content.

go 1.21.0

use .

We are going to add our locally external package to our go.work file; for this, we execute the following command.

go work use ../blog_go_work_pkg

Our go.work would look like this:

go 1.21.0

use (
    .
    ../blog_go_work_pkg
)

In our project, we are going to define the values for the 'LastName' and 'Country' fields.

func main() {
    u := domain.User{
      ID:        "1231",
      FirstName: "Nahuel",
      LastName:  "Costamagna",
      Country:   "Argentina",
    }

    value, _ := json.Marshal(u)
    fmt.Println(string(value))
}

we execute the program and see the result

{"id":"1231","first_name":"Nahuel","last_name":"Costamagna","country":"Argentina"}

In this way, we obtain our 'blog_go_work_pkg' local package instead of the remote package on GitHub.

We can remove the external package from our project using the following command.

go work edit -dropuse ../blog_go_work_pkg

and we see the content of our 'go.work' file.

go 1.21.0

use .

Of course, we can remove it directly from our 'go.work' file without the need to execute a command.

We run the program again and can see the error because we are using the externally hosted package instead of the local one.

# command-line-arguments
./main.go:13:3: unknown field LastName in struct literal of type domain.User
./main.go:14:3: unknown field Country in struct literal of type domain.User

Conclusion

With this functionality, we can use our imported package locally without the need to upload it to the repository or use replace in our go.mod file. For more information, you can refer to the official documentation

Nahuel Costamagna

Nahuel Costamagna

FullStack Developer & DevOps