Go Workspaces and Vendoring
Real projects span multiple modules and must build the same way everywhere. You'll use go work init / use and the go.work file to develop modules together, compare workspaces with replace , vendor dependencies with go mod vendor , and lock things down with GOFLAGS=-mod=vendor , GOPROXY , and go.sum for reproducible builds.
Learn Go Workspaces and Vendoring in our free Go course — an interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ Creating a workspace
go work init creates a go.work file and go work use adds local module directories. Now one module builds against your local copy of another — no replace lines, no publishing first.
2️⃣ The go.work file
The go.work file lists member modules in a use block. It describes a local layout, so teams often gitignore it. Check the active file with go env GOWORK .
3️⃣ Workspaces vs replace
A replace directive edits the committed go.mod and can leak a local path into a release. A workspace keeps that wiring in go.work , so go.mod stays clean and publishable.
4️⃣ Vendoring and reproducible builds
go mod vendor copies dependencies into vendor/ for self-contained, offline builds. GOPROXY controls where modules are fetched, and go.sum checksums lock their exact content.
🎯 Your Turn
Set up a workspace for two local modules. Fill in the two blanks marked ___ to create it and add the second module.
❌ Committing a local replace to go.mod — it can ship in a release.
✅ Use a go.work workspace for local wiring instead.
❌ Committing go.work by accident — forces your layout on everyone.
✅ Gitignore it; let each developer (and CI) resolve modules normally.
❌ Editing vendor/ by hand — it drifts from go.mod .
✅ Regenerate with go mod vendor after any dependency change.
❌ Deleting or distrusting go.sum — breaks reproducibility.
✅ Keep go.sum committed; it verifies every dependency's content.
go work use ./mod . go work init creates the go.work file first.
go.sum checksums (plus pinned versions and a stable GOPROXY or vendor/ ).
Tidy, vendor, and build a module with GOFLAGS=-mod=vendor so a teammate or CI can build it with no network, getting identical dependencies via go.sum .
Practice quiz
What problem do Go workspaces (Go 1.18+) solve?
- developing multiple local modules together without editing each go.mod
- compiling C code
- running tests in parallel
- downloading the standard library
Answer: developing multiple local modules together without editing each go.mod. A workspace lets you work on several modules at once locally, so changes in one are seen by another without replace edits.
Which command creates a go.work file?
- go work new
- go init work
- go work init
- go mod init
Answer: go work init. go work init [dirs...] creates a go.work file; go work use adds module directories to it.
What does go work use ./mymod do?
- downloads mymod
- adds the local module directory to the workspace
- deletes the module
- runs its tests
Answer: adds the local module directory to the workspace. go work use registers a local module directory in go.work so the workspace builds against your local copy.
Where does the go.work file usually live, and is it committed?
- in the home directory only
- it is generated at build time
- inside each module; always committed
- above the modules; often left OUT of version control as a local dev convenience
Answer: above the modules; often left OUT of version control as a local dev convenience. go.work typically sits above the member modules and is frequently gitignored since it reflects a local layout.
How do workspaces compare to a replace directive in go.mod?
- workspaces avoid editing/committing each go.mod; replace changes the module file itself
- replace is newer than workspaces
- workspaces only work in CI
- they are identical in every way
Answer: workspaces avoid editing/committing each go.mod; replace changes the module file itself. A workspace keeps local wiring out of go.mod; replace edits the committed module file, which can leak into releases.
What does go mod vendor create?
- a go.work file
- a vendor/ directory containing copies of all dependencies
- a compiled binary
- a test report
Answer: a vendor/ directory containing copies of all dependencies. go mod vendor copies the module's dependencies into a top-level vendor/ directory for self-contained builds.
When a vendor/ directory is present, how does the go command behave by default?
- it always re-downloads
- it errors out
- it ignores vendor/
- it builds using the vendored copies (-mod=vendor) automatically
Answer: it builds using the vendored copies (-mod=vendor) automatically. If vendor/ exists and is consistent, recent Go versions default to -mod=vendor and build from it without network access.
What does the GOFLAGS=-mod=vendor environment setting do?
- sets the Go version
- disables modules
- forces builds to use the vendor/ directory
- enables the race detector
Answer: forces builds to use the vendor/ directory. GOFLAGS=-mod=vendor makes every go command use vendored dependencies, useful in locked-down or offline CI.
What is GOPROXY?
- a linter
- the module proxy URL(s) the go command fetches modules through
- a build cache directory
- a test runner
Answer: the module proxy URL(s) the go command fetches modules through. GOPROXY (default proxy.golang.org,direct) controls where modules are downloaded from; you can set a private proxy.
Which practice most helps REPRODUCIBLE builds?
- pinning versions in go.mod/go.sum and using a proxy or vendor/ so the same dependencies resolve every time
- disabling go.sum
- always using the latest version
- editing go.mod by hand each build
Answer: pinning versions in go.mod/go.sum and using a proxy or vendor/ so the same dependencies resolve every time. go.sum checksums plus pinned versions (and a proxy or vendored copies) ensure everyone builds the exact same code.