Installing Go and Hello, World
You're going to write and run a real Go program in the next few minutes. Not a REPL snippet — a file, compiled and executed by the same toolchain you'd use to ship production code.
Install Go
Go ships as a single toolchain — no separate package manager to install first, no virtual environment to set up. Grab it from go.dev/dl for your OS, or use a package manager:
# macOS
brew install go
# Ubuntu/Debian
sudo apt install golang-goConfirm it worked:
go versionYou should see something like go version go1.23.0 darwin/arm64.
Write the smallest Go program
Create a file called main.go:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go")
}Every executable Go program has exactly this shape, and each line is doing something specific:
package main— this file belongs to themainpackage, which is what makes it a program you can run, not just a library other code imports.import "fmt"— pulls in the standard library's formatting/printing package. Go's standard library is large and genuinely good; you'll reach for it constantly.func main()— the entry point. When you run the program, this is where execution starts. There's no ambiguity about "what runs first" the way there can be in a script with top-level statements — in Go, it's alwaysmain().
Run it
go run main.goYou should see:
Hello, Gogo run compiles the file to a temporary binary and executes it in one step — the fast loop for trying things out. When you want an actual binary you can hand to someone else:
go build main.go
./maingo build produces a single, statically linked executable — no runtime to install on the machine that runs it, no node_modules, no interpreter version to match. That's a large part of why Go is a common choice for command-line tools and small services: you build once and ship a file.
A note if you're coming from Python
Two habits to unlearn early:
- Every file that's part of a build must compile. There's no equivalent of running one function in a file that has an unrelated syntax error somewhere else — Go compiles the whole package before anything runs.
- Unused imports and unused local variables are compile errors, not warnings. Import
fmtand then never call anything from it, andgo runrefuses to run at all. This feels strict at first; in practice it means a Go codebase rarely accumulates the slow drift of dead imports and copy-pasted-then-abandoned variables that's easy to ignore in a more permissive language.