Even though Go (Golang) is known for its simplicity, new (and even experienced) developers often fall into traps that lead to bugs, inefficiency, or unidiomatic code. Understanding these pitfalls early can save you hours of debugging and make your codebase cleaner and more maintainable.
Here are the 10 most common mistakes Go developers make — and how you can avoid them.
1. Ignoring Error Handling
Mistake: Writing code like this:
data, _ := ioutil.ReadFile("config.json")
This ignores potential errors and can cause unexpected crashes.
Fix: Always handle errors explicitly:
data, err := ioutil.ReadFile("config.json")
if err != nil {
log.Fatalf("failed to read file: %v", err)
}
2. Overusing Global Variables
Mistake: Relying on global state for config, database connections, or caches.
This makes code hard to test and maintain.
Fix: Use dependency injection — pass dependencies through constructors or function parameters.
3. Misusing Goroutines
Mistake: Spawning goroutines without managing their lifecycle.
go doWork()
This can cause goroutine leaks.
Fix: Use sync.WaitGroup
or context.Context
for proper cancellation and cleanup.
4. Not Closing Resources
Mistake: Forgetting to close files, DB connections, or HTTP responses.
Fix: Always use defer
:
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
5. Using init()
Excessively
Mistake: Filling init()
with logic makes programs harder to test and reason about.
Fix: Keep init()
minimal (only setup). Put business logic in clearly defined functions.
6. Reinventing the Wheel
Mistake: Writing your own JSON parser, web framework, or ORM.
Fix: Go has a strong standard library (net/http
, encoding/json
) and mature external libraries (Gin, GORM, sqlc). Don’t reinvent what already exists.
7. Ignoring Concurrency Safety
Mistake: Writing to shared variables without synchronization.
counter := 0
go func() { counter++ }()
Fix: Use channels or sync.Mutex
to protect shared state.
8. Poor Package Organization
Mistake: Dumping all code into the main
package or creating unnecessary nested packages.
Fix: Follow idiomatic structure:
/cmd/app-name/main.go
/internal/yourpackage/
Keep packages small, focused, and reusable.
9. Neglecting Tests
Mistake: Skipping tests or writing only “happy path” cases.
Fix: Write table-driven tests, use mocks (testify/mock
), and run go test -race
to catch data races.
10. Ignoring Performance Profiling
Mistake: Guessing where bottlenecks are instead of measuring.
Fix: Use Go’s built-in tools:
go test -bench .
go tool pprof cpu.prof
Rely on evidence, not assumptions, to optimize code.
Conclusion
Go’s simplicity is one of its greatest strengths, but it doesn’t protect developers from making mistakes. By handling errors carefully, organizing packages properly, managing goroutines, and leveraging Go’s built-in tools, you’ll write cleaner, faster, and more idiomatic code.
Avoiding these 10 mistakes will make you a much more effective Go developer — and keep your projects stable in production.