Introduction to Go
Why Go
Section titled “Why Go”Go was designed at Google by Rob Pike, Ken Thompson, and Robert Griesemer, first released in 2009. It targets the niche between systems languages (C, C++) and managed languages (Java, Python): fast Compilation, native performance, garbage collection, and built-in concurrency primitives.
Core design goals:
Simplicity. The language spec is ~50 pages. There are no exceptions, no inheritance, no operator overloading, no macros. Features are additive, not combinatorial — the number of concepts you must hold in your head grows linearly with the language, not exponentially.
Fast compilation. Dependency-aware compilation, minimal syntax, and no header files mean large codebases compile in seconds, not minutes.
Concurrency as a first-class citizen. Goroutines are multiplexed onto OS threads by the runtime scheduler. Channels provide safe communication between goroutines without locks.
Static typing with inference. Types are checked at compile time, but the compiler infers types where unambiguous. This catches bugs early without the verbosity of explicit annotations everywhere.
Compilation Model
Section titled “Compilation Model”Go compiles to native machine code. There is no VM, no interpreter, no JIT.
Source (.go) -> go build -> linker -> native binary (statically linked by default)The compiler pipeline:
- Lexing and parsing -> AST
- Type checking -> resolves all types, verifies correctness
- SSA-based optimization -> intermediate representation for optimizations
- Machine code generation -> targets the native architecture
The resulting binary is statically linked by default (on Linux/macOS), containing the Go runtime, Garbage collector, and all dependencies. No external shared libraries are required at runtime.
Installation
Section titled “Installation”Download from go.dev/dl or use a package manager:
## Linux (snap)sudo snap install go --classic
## macOS (homebrew)brew install go
# Verifygo versionSet up workspace environment variables:
# GOPATH is where Go stores downloaded modules and built binaries# Default is $HOME/gogo env GOPATH
# GOROOT is where Go is installed (in most cases auto-detected)go env GOROOTHello World
Section titled “Hello World”package main
import "fmt"
func main() { fmt.Println("Hello, World!")}Run directly:
go run main.goBuild a binary:
go build -o hello main.go./helloEvery Go file belongs to a package. Executables must be in package main and expose a func main(). Library packages use any other name and are imported by path.
The Go Toolchain
Section titled “The Go Toolchain”go run
Section titled “go run”Compiles and executes one or more .go files in a temporary directory. Useful for development and One-off scripts. Does not produce a persistent binary.
go run .go run main.gogo run cmd/server/main.gogo build
Section titled “go build”Compiles packages and dependencies, producing a binary. By default, the binary is named after the Directory containing package main.
go build # binary named after current directorygo build -o myapp # custom output namego build -ldflags "-s -w" # strip debug info, reduce binary sizego build -race # enable race detectorCross-compilation is trivial — set GOOS and GOARCH:
GOOS=linux GOARCH=amd64 go build -o myapp-linuxGOOS=windows GOARCH=amd64 go build -o myapp.exeGOOS=darwin GOARCH=arm64 go build -o myapp-macgo install
Section titled “go install”Builds and installs the binary to $GOPATH/bin (or $GOBIN if set). This is how CLI tools are Installed from source.
go install golang.org/x/tools/gopls@latestgo fmt / gofmt
Section titled “go fmt / gofmt”Formats Go source code according to the standard style. There is no configuration — the format is Canonical. This eliminates style debates in code reviews.
go fmt ./...go vet
Section titled “go vet”Examines source code and reports suspicious constructs. Catches bugs that the compiler does not.
go vet ./...go doc
Section titled “go doc”Prints documentation for packages and symbols.
go doc fmt.Printlngo doc net/httpProject Structure
Section titled “Project Structure”A minimal Go project:
myproject/ go.mod main.go internal/ db/ db.go cmd/ server/ main.goThe internal/ directory is special: packages inside internal cannot be imported by packages Outside the module tree rooted at the parent of internal. This enforces encapsulation.
The cmd/ directory convention holds executable entry points.
Go Modules
Section titled “Go Modules”Since Go 1.16, modules are the default dependency management system. A go.mod file declares the Module path and dependency requirements:
module github.com/you/myproject
go 1.22
require ( github.com/go-chi/chi/v5 v5.0.12 github.com/lib/pq v1.10.9)Key module commands:
go mod init github.com/you/myproject # initializego mod tidy # sync dependencies with sourcego mod download # download modules to cachego mod verify # verify checksumsgo mod graph # print dependency graphgo list -m all # list all dependenciesgo.sum records the expected cryptographic checksums of every dependency. It should be committed to Version control and never edited manually.
Where Go Runs
Section titled “Where Go Runs”| Target | Use Case |
|---|---|
| Linux (amd64, arm64) | Servers, containers, cloud |
| macOS (amd64, arm64) | Desktop development |
| Windows (amd64) | Desktop applications |
| WebAssembly (wasm) | Browser, edge computing |
| FreeBSD/OpenBSD | Networking, infrastructure |
| Embedded (GOOS=linux GOARCH=arm) | IoT, routers, ARM devices |
Common Pitfalls
Section titled “Common Pitfalls”Not setting
GOPATH/GOBINon$PATH.go installplaces binaries in$GOPATH/binor$GOBIN. If this is not on your PATH, installed tools will not be found.Using
go runin production.go runcompiles to a temp directory and does not produce an artifact. Usego buildto produce a deployable binary.Ignoring
go vet. Rungo vet ./...before every commit. It catches real bugs: unreachable code, incorrect format strings, lock copies, and more.Not committing
go.sum. Thego.sumfile is essential for reproducible builds. Always commit it alongsidego.mod.Using
latestingo installwithout pinning.go install tool@latestalways fetches the newest version. Pin versions ingo.modfor reproducible builds.Circular imports. Go does not allow circular imports between packages. If A imports B and B imports A, the compiler rejects it. Restructure by extracting the shared code into a third package.
Intuition
Section titled “Intuition”Go is the language of simplicity at scale. It was designed at Google to solve the problem of large codebases with many contributors: fast compilation, clear syntax, and built-in concurrency. Goroutines are lightweight threads managed by the Go runtime, and channels are the pipes that connect them. Go intentionally omits features like inheritance, generics (until 1.18), and exceptions, favouring composition, error values, and explicit error handling. The result is code that looks similar across teams and projects.