DEV Community

Cover image for The Go Workspaces Feature You're Probably Not Using Enough
Mateusz Piórowski
Mateusz Piórowski

Posted on

The Go Workspaces Feature You're Probably Not Using Enough

So you're building a Go project. It starts simple, as they all do. Then it grows. Now you have a main API service, a separate service for handling background jobs, and you've been a good developer and put all your common code into a shared pkg directory. Things like authentication helpers, database models, all the stuff both services need.

This is a great pattern. Until you need to change something in the pkg directory.

Now you're stuck. You make a change in pkg, but your API service doesn't see it. Why? Because its go.mod file is pointing to the version on GitHub, not your local version. So you add a replace directive. Then you have to do the same thing for your worker service. And you have to remember to take them out before you commit, otherwise, you'll break the build for everyone else.

It's a total mess and super easy to forget.

There Is a Better Way, and It's Called Workspaces

Go workspaces are the official, built-in solution to this exact problem. It's a simple feature that tells the Go compiler, "Hey, when you're building my project, I want you to use these specific modules from my local disk, not the ones from the internet."

You do this with a single file in the root of your project called go.work. This file tells Go which local modules are part of your active development "workspace."

Let's look at how this works with our example. Imagine you have a project structured like this:

/my-cool-project
|-- /app
    |-- go.work
    |-- /service-core
    |   |-- go.mod
    |-- /service-admin
    |   |-- go.mod
    |-- /pkg
        |-- /auth
        |-- /str

Enter fullscreen mode Exit fullscreen mode

Both service-core and service-admin need code from the pkg directory. Instead of messing with replace directives, your go.work file would just look like this:

use (
    ./service-core
    ./service-admin
    ./pkg
)
Enter fullscreen mode Exit fullscreen mode

And... that's it. Seriously.

Now, whenever you're working inside the /app directory, Go automatically knows that if service-core imports something from pkg, it should use the pkg directory right there on your hard drive. No go.mod changes needed. It's seamless.

Getting Started Is Easy

You can start using this in your projects today.

  1. Go to the root of your project where your services live.

  2. Run go work init ./service-one ./service-two ./my-shared-lib. This creates the go.work file.

  3. If you add a new service later, just run go work use ./new-service.

It's a small change to your workflow that makes a huge difference.

Don't Forget to Sync Your Work

The go work sync command updates the go.mod files for every module inside your workspace.

While the go.work file tells Go to use your local modules for development, your go.mod files are what define the real dependencies for your CI/CD pipelines and for other developers.

go work sync synchronizes the dependencies from your workspace back to each module's go.mod file. This ensures they are accurate and up-to-date before you commit your changes, preventing broken builds for your team.

You should run it from your project root after you've finished your local changes:

go work sync
Enter fullscreen mode Exit fullscreen mode

Why You Should Be Using This

To put it simply, workspaces make developing with multiple modules and shared libraries a breeze.

  • You can finally make changes in a shared library and see them instantly in your other services.
  • Your go.mod files stay clean and only describe your real, committed dependencies.
  • You'll never accidentally commit a replace directive again.

If you want to see a project that's built from the ground up using this philosophy, you should check out my Go CLI builder - GoFast. It uses workspaces to manage its core services and shared packages, making it a great real-world example of how to build scalable, maintainable Go applications. And MUCH more :).

Hope you enjoyed it, have a good day!

Top comments (0)