Go workspaces enable working with multiple modules simultaneously. Introduced in Go 1.18, workspaces simplify development when you need to make changes across multiple modules.
Overview
Workspaces allow you to:
Work on multiple modules at once
Make coordinated changes across modules
Test changes before publishing
Avoid manual replace directives
Workspaces are configured via a go.work file and are intended for local development. The go.work file should not be committed to version control.
Creating a Workspace
Initialize Workspace
Create a workspace in a parent directory: go work init ./module1 ./module2
This creates a go.work file: go 1.21
use (
. / module1
. / module2
)
Verify Workspace
Check which workspace file is being used:
Work Across Modules
Changes in one module are immediately visible to others: cd module1
go build # Uses local module2 if imported
The go.work File
Structure
go 1.21
use (
. / module1
. / module2
. / apps / webapp
)
replace example . com / old => example . com / new v1 . 0.0
Directives
Specifies the Go version:
Lists modules in the workspace: use . / module1
use . / module2
// Or as a block
use (
. / module1
. / module2
)
Replaces module paths (same as in go.mod): replace example . com / pkg => .. / other - pkg
replace example . com / old v1 . 0 . 0 => example . com / new v1 . 1.0
Workspace replaces take precedence over go.mod replaces.
Workspace Commands
go work init
Initialize a new workspace:
# Create empty workspace
go work init
# Create with modules
go work init ./module1 ./module2
# Create in specific directory
cd ~/projects/myworkspace
go work init ./api ./lib ./cmd
go work use
Add or update modules in workspace:
Add Modules
Remove Modules
# Add single module
go work use ./module3
# Add multiple modules
go work use ./module1 ./module2
# Add all modules in directory recursively
go work use -r ./packages
go work edit
Edit go.work file programmatically:
Add/Drop Use Directives
Replace Directives
Set Go Version
Format and Print
# Add use directive
go work edit -use=./newmodule
# Drop use directive
go work edit -dropuse=./oldmodule
go work sync
Sync workspace dependencies:
This updates go.mod files in all workspace modules to match the workspace’s build list.
Run go work sync after adding dependencies to ensure all modules use consistent versions.
go work vendor
Create vendor directory for workspace:
# Create vendor directory
go work vendor
# Verbose output
go work vendor -v
# Custom output directory
go work vendor -o ./vendor-dir
Example Workspace Setup
Project Structure
myproject/
├── go.work
├── api/
│ ├── go.mod
│ └── main.go
├── lib/
│ ├── go.mod
│ └── lib.go
└── cmd/
├── go.mod
└── main.go
Setting Up
Create Modules
mkdir -p myproject/{api,lib,cmd}
cd myproject
# Initialize each module
cd api && go mod init example.com/api && cd ..
cd lib && go mod init example.com/lib && cd ..
cd cmd && go mod init example.com/cmd && cd ..
Create Workspace
cd myproject
go work init ./api ./lib ./cmd
Creates go.work: go 1.21
use (
. / api
. / cmd
. / lib
)
Import Local Modules
In api/main.go: package main
import " example.com/lib "
func main () {
lib . DoSomething ()
}
No replace directives needed!
Working with Workspaces
Building and Testing
# Build from any workspace module
cd api
go build # Automatically uses local ./lib
# Test all workspace modules
go test ./...
# Build specific module
go build -C ./api
# Run from workspace root
go run ./api
Adding Dependencies
# Add dependency to specific module
cd api
go get github.com/gorilla/mux
# Sync workspace
go work sync
Checking Workspace Status
# Show active workspace
go env GOWORK
# List workspace modules
go list -m
# Show all modules in workspace
go work edit -print
Workspace vs Replace Directives
Before Workspaces (go.mod)
module example . com / api
replace example . com / lib => .. / lib
require example . com / lib v0 . 0.0
With Workspaces (go.work)
module example . com / api
require example . com / lib v0 . 0.0
Replace Directives
Requires manual editing
Per-module configuration
Often committed by accident
Can be confusing
Workspaces
Centralized configuration
Automatic module discovery
Not committed to VCS
Cleaner go.mod files
Disabling Workspaces
Temporary Disable
# Disable workspace for single command
GOWORK = off go build
# Unset GOWORK
export GOWORK = off
go build
Using Different Workspace
# Use specific workspace file
GOWORK = /path/to/other.work go build
# Or set default
go env -w GOWORK=/path/to/other.work
Multi-Repository Workflows
Cloning Multiple Repositories
# Clone repositories
mkdir workspace
cd workspace
git clone https://github.com/user/module1
git clone https://github.com/user/module2
git clone https://github.com/user/app
# Create workspace
go work init ./module1 ./module2 ./app
Making Changes Across Repos
Make Changes
# Edit module1
cd module1
# make changes...
# Edit app to use new module1 features
cd ../app
# make changes...
Test Together
# Test from workspace root
go test ./...
Commit and Publish
# Commit module1 changes
cd module1
git add -A
git commit -m "Add new feature"
git push
git tag v1.2.0
git push --tags
# Update app to use published version
cd ../app
go get github.com/user/[email protected]
git add -A
git commit -m "Use module1 v1.2.0"
git push
Best Practices
Don't Commit go.work Add to .gitignore - it’s for local development only
Use work sync Keep module versions consistent across workspace
One Workspace Per Project Avoid overlapping or nested workspaces
Clean go.mod Remove replace directives when using workspaces
.gitignore
# Don't commit workspace file
go.work
go.work.sum
CI/CD Considerations
Workspaces are disabled in CI by default (no go.work file):
name : CI
on : [ push , pull_request ]
jobs :
test :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- uses : actions/setup-go@v5
with :
go-version : '1.21'
# Each module tested independently
- run : cd api && go test ./...
- run : cd lib && go test ./...
- run : cd cmd && go test ./...
Use Cases
Developing a Library and Its Consumers
workspace/
├── go.work
├── mylib/ # Library being developed
│ └── go.mod
├── example1/ # Example application
│ └── go.mod
└── example2/ # Another application
└── go.mod
Monorepo Development
monorepo/
├── go.work
├── services/
│ ├── api/
│ ├── worker/
│ └── scheduler/
├── pkg/
│ ├── common/
│ ├── database/
│ └── auth/
└── tools/
└── migrator/
Testing Unreleased Changes
# Clone your fork
git clone https://github.com/you/upstream-fork lib
# Your application
cd myapp
go work init . ../lib
# Test with unreleased changes
go test ./...
Troubleshooting
Module not found in workspace
# Check workspace modules
go work edit -print
# Add missing module
go work use ./missing-module
# Verify
go list -m
# Check GOWORK setting
go env GOWORK
# Should show path to go.work file
# If empty, create workspace:
go work init ./module1 ./module2
Version conflicts between modules
# Sync workspace build list
go work sync
# Check dependency versions
go list -m all
# View dependency graph
go mod graph
Migration from Replace Directives
Create Workspace
go work init ./module1 ./module2
Remove Replace Directives
Edit each module’s go.mod and remove local replace directives: module example.com/app
require example.com/lib v1.0.0
-replace example.com/lib => ../lib
Verify
go build ./...
go test ./...
Update .gitignore
echo "go.work" >> .gitignore
echo "go.work.sum" >> .gitignore
See Also
Modules Go modules fundamentals
go Command Overview of go command
Building Building Go programs
References