Before modules, Go had this weird requirement where all your code had to live under one specific directory tree. Not just your current project - everything. Your personal projects, work stuff, random tutorials - all crammed into $GOPATH/src/github.com/whoever/whatever
.
I've onboarded maybe 20 developers over the years. Every single fucking one got confused by GOPATH. It's like explaining why we used to store files on floppy disks - technically it worked, but who thought this was a good idea?
The Old Nightmare
GOPATH forced this rigid directory structure that made no sense to anyone. Want to work on two projects that need different versions of the same library? Nope, not happening. You got one version of everything, globally.
Import paths had to match the directory structure exactly. Watched a developer spend an hour debugging because they cloned a repo to their Desktop instead of the magical GOPATH location. The compiler just said "can't find package" - no hint about GOPATH, no suggestion about directory structure, nothing useful.
New developer onboarding always went the same way:
- "Why won't my code compile?"
- "Did you set up GOPATH?"
- "What's GOPATH?"
- Me explaining why Go decided to reinvent directory organization
The worst part? Explaining to someone coming from Python or Node.js why they couldn't just put their project wherever made sense.
Modules: How It Should Have Been From Day One
Run go mod init
in any directory and you're done. No special folder structure, no environment variables, no explaining to junior developers why their perfectly reasonable file organization is wrong.
go.mod tells Go what you need:
module myproject
go 1.23
require github.com/gin-gonic/gin v1.9.1
go.sum contains checksums for everything:
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
Run go mod tidy
and Go downloads everything to a shared cache in your home directory. Your project folder stays clean - no giant node_modules directory eating disk space. If the checksums don't match, Go refuses to install anything. Simple and secure.
Minimal Version Selection (Because Latest != Best)
Here's where Go got it right: it doesn't automatically update everything to the newest version like npm does.
If your project needs library A v1.2+ and another dependency needs A v1.4+, Go uses v1.4. Not v1.9 that came out yesterday and might break everything.
This prevents those fun Monday mornings when your build suddenly shits the bed because someone released a "minor" update that changed the API. Had a React project break production because react-router 6.4.1 to 6.4.2 changed how location state worked - "patch" release, my ass.
The Go team's MVS design is predictable and boring. When you're trying to ship features instead of debugging dependency conflicts, boring is exactly what you want.
No Configuration Bullshit
Maven has XML files longer than most novels. npm has package.json files with more scripts than a Hollywood production. Python has requirements.txt files that drift out of sync with reality.
Go modules: run go mod init
and start coding. That's it.
The go.mod file starts with 3 lines and only grows when you actually add dependencies. No build scripts, no bundler configuration, no wondering why your coworker's laptop builds successfully but yours doesn't.