Free Handbook · Every example compiled & verified

Go Handbook

Learn Go the way it is written at work. Seventeen modules from your first program to a job: every example program was compiled and run with the real Go toolchain before publishing, with its output shown exactly as it printed, and the real compiler errors and runtime panics you will hit are explained with the fix. Variables and types, flow control, functions and closures, slices and maps, structs and methods, interfaces, errors as values, goroutines and channels, packages, modules and testing, generics, debugging, Go with net/http, Gin, PostgreSQL, Redis, Docker, Kubernetes, Prometheus and Kafka, data structures and algorithms, problem-solving patterns, interview questions, a certification exam, and a resume check at the end.

0 / 134 lessons🔥 0 day streak
ShareXLinkedIn

How this handbook works

Every lesson has a complete Go program with the exact output it prints — each one compiled and run with the real Go toolchain before it was published, so what you see is what you will get when you run it yourself — a trace of what the program did line by line where that matters, and the real compiler or runtime error you will hit next, with why it happened and the fix. Lessons tick themselves as you go. Finish the handbook, sit the exam, get the certificate, then take your resume through the ATS checker against a real job posting.

17modules
134lessons
117compiled examples
64real errors explained

Module 00 · what you'll be able to do

  • Explain what Go is good at and where it is used: cloud infrastructure, Docker and Kubernetes, backend services and CLIs
  • Install the Go toolchain on macOS, Windows or Linux and check it with go version
  • Create a module with go mod init, then run a program with go run and build it with go build
  • Read the parts of a Go program: package clause, imports, func main, comments and exported names
  • Format code with gofmt and catch mistakes with go vet before anyone reviews it
01

Why learn Go

Go (often called Golang, after its old website golang.org) is a small, compiled, statically typed language designed at Google by Robert Griesemer, Rob Pike and Ken Thompson and released as open source in 2009. It was built to fix the problems of large teams writing server software: slow builds, tangled dependencies and code that every engineer formats differently. The answer was a deliberately small language — about 25 keywords — that compiles in seconds to a single native binary and has concurrency built into the language itself.

That design made Go the language of cloud infrastructure. Docker, Kubernetes, Terraform, Prometheus, etcd, Consul, Caddy and the Grafana backend are all written in Go. If a company runs containers, it runs Go code every day, whether its own engineers write Go or not.

Where Go is usedReal examplesWhy Go fits
Cloud and container infrastructureDocker, Kubernetes, containerd, etcdOne static binary, low memory, easy concurrency
DevOps and CLI toolsTerraform, Hugo, the GitHub CLI (gh), kubectlCross-compiles to every OS from one machine; no runtime to install
Backend APIs and microservicesPayment, streaming and ride-sharing backendsFast startup, a production-grade HTTP server in the standard library
Observability and networkingPrometheus, Grafana, Caddy, TraefikGoroutines handle thousands of connections cheaply
Data plumbingQueue consumers, log shippers, ETL workersPredictable performance without JVM tuning
What Go jobs actually look like
Go roles are usually titled Backend Engineer, Platform Engineer, Site Reliability Engineer or Cloud/Infrastructure Engineer. The day-to-day is HTTP and gRPC services, Kubernetes operators, CLIs and internal tooling. Very few Go jobs are "Go only" — they expect Docker, Kubernetes, SQL and one cloud. Module 16 covers the resume and portfolio side.

What Go gives you

  • Compiles to one native binary — copy it to a server and run it
  • Builds in seconds, even for large projects
  • Goroutines and channels for concurrency, in the language
  • A big standard library: HTTP server, JSON, crypto, testing
  • One official format (gofmt), so all Go code looks the same

What Go deliberately leaves out

  • No classes or inheritance — structs, methods and interfaces instead
  • No exceptions — errors are ordinary return values
  • No ternary operator, no while loop (for does everything)
  • No function overloading or default arguments
  • Generics exist (since Go 1.18) but are intentionally simple
02

Install Go on macOS, Windows or Linux

Download the official installer from go.dev/dl, or use your system's package manager. This handbook targets Go 1.22 or newer and every example was run on the current release. A few newer helpers are marked with the version that added them where they appear (b.Loop needs Go 1.24, sync.WaitGroup.Go needs 1.25), so install the latest release and everything here works as shown.

bashmacOS
# Homebrew
brew install go

# or download the .pkg installer from https://go.dev/dl and double-click it
go version
bashWindows (PowerShell)
# winget (built into Windows 10 and 11)
winget install GoLang.Go

# or download the .msi installer from https://go.dev/dl
# open a NEW terminal so PATH is refreshed, then:
go version
bashLinux
# official tarball (replace the version with the latest from go.dev/dl)
curl -LO https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
source ~/.profile
go version

Distribution packages (apt install golang-go) often ship an older Go. The official tarball is the safe choice.

go version should print something like go version go1.23.4 darwin/arm64. If the shell says command not found, the Go bin directory is not on your PATH — open a new terminal first, then check your shell profile.

Pick an editor with the Go extension
VS Code with the official Go extension, or JetBrains GoLand, both install gopls (the Go language server). You get autocomplete, jump-to-definition, and formatting on every save — which means you never argue about indentation again.
03

Your first program: go mod init and go run

Every Go project lives in a module: a folder with a go.mod file that names the project and records its dependencies. Create one with go mod init and a module path — for a project you might publish, that is usually a repository path like github.com/you/hello; for practice, any name works.

bashterminal
mkdir hello && cd hello
go mod init example.com/hello
# go: creating new go.mod: module example.com/hello

# create main.go (below), then:
go run .
# Hello, Go!
gomain.go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Go!")
}
Outputcompiled & run with real Go
Hello, Go!
Your turn

Change the message, then add a second fmt.Println line that prints your name. Run it again with go run .

go run compiles the program into a temporary binary, runs it, and throws the binary away. It is what you use while writing code. go run . runs the package in the current folder; go run main.go runs one file (fine for the single-file examples in this handbook).

Error you will hit

imported and not used

go
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Println("Hello, Go")
}
# command-line-arguments
./main.go:5:2: "os" imported and not used
Why the compiler said that

Go refuses to compile a file that imports a package it never uses. This is not a warning you can ignore: unused imports slow builds and hide dead code, so the compiler treats them as errors. Beginners hit this constantly when they comment out a line that used the package.

The fix

Delete the unused import. Editors with gopls (or the goimports tool) add and remove imports automatically on save.

go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Go")
}
Error you will hit

Opening brace on its own line

go
package main

import "fmt"

func main()
{
	fmt.Println("Hello, Go")
}
# command-line-arguments
./main.go:6:1: syntax error: unexpected semicolon or newline before {
Why the compiler said that

Go's grammar uses semicolons, but you never type them: the lexer inserts one automatically at the end of a line that ends in an identifier, a literal or a closing bracket. func main() ends in ), so a semicolon is inserted there — and the { on the next line is left dangling.

The fix

Put the opening brace on the same line as the statement it belongs to. This is one rule gofmt cannot fix for you, because the code does not parse.

go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Go")
}
04

How a Go program is structured

A Go source file always has the same three parts, in this order: a package clause, the imports, and then the declarations (functions, types, variables, constants). An executable program must be in package main and must have a func main() with no parameters and no return value — that is where execution starts.

gomain.go
// Package main is the entry point of an executable program.
package main

import (
	"fmt"
	"strings"
)

// greeting is package-level: visible to every function in the package.
const greeting = "hello"

/*
   Block comments exist, but Go code
   almost always uses // line comments.
*/
func main() {
	loud := strings.ToUpper(greeting) // call an exported function
	fmt.Println(loud, "from", "main")
}
Outputcompiled & run with real Go
HELLO from main
Your turn

Use strings.Repeat(greeting, 3) to print hellohellohello.

VisualizeWhat happens when the program runsStep 1 / 6
package main
import (
"fmt"
"strings"
)
const greeting = "hello"
func main() {
loud := strings.ToUpper(greeting)
fmt.Println(loud, "from", "main")
}
Line 1

The file belongs to package main, which tells go build to produce an executable instead of a library.

Variables now

nothing yet

All 6 steps as a table
StepLineWhat happenedVariables now
11The file belongs to package main, which tells go build to produce an executable instead of a library.
24Two standard-library packages are imported. Inside this file they are referred to by their last path element: fmt and strings.
38A package-level constant is set before main runs.greeting = "hello"
410The runtime calls main. When it returns, the program exits with status 0.
511strings.ToUpper returns a new string; := declares loud and infers its type as string.greeting = "hello" loud = "HELLO"
612fmt.Println prints its arguments separated by spaces and ends with a newline.
Capital letter = exported
Go has no public or private keywords. A name that starts with an upper-case letter (Println, ToUpper) is exported — usable from other packages. A lower-case name (greeting) is visible only inside its own package. That is the entire access-control system.
Error you will hit

package is not a main package

go
package hello

import "fmt"

func main() {
	fmt.Println("Hello, Go")
}
package command-line-arguments is not a main package
Why the compiler said that

Only package main produces a runnable program. Any other package name makes the file a library, so go run has nothing to execute — even though a function called main exists. (command-line-arguments is the name Go gives a package built from files listed on the command line.)

The fix

Name the package main for anything you want to run.

go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Go")
}
05

go build: one static binary

go build compiles your module into a single executable file. By default a pure-Go program is statically linked: the binary contains your code, every package it imports and the Go runtime (garbage collector and goroutine scheduler). Copy that one file to a server with the same OS and CPU and it runs — no Go install, no virtual machine, no dependency folder.

bashterminal
go build            # produces ./hello (hello.exe on Windows)
./hello
# Hello, Go!

go build -o bin/api .   # choose the output path

# cross-compile from your laptop for a Linux server
GOOS=linux GOARCH=amd64 go build -o hello-linux .

# a smaller release binary: strip debug info
go build -ldflags="-s -w" -o hello .

Cross-compiling is two environment variables. No extra toolchain is needed for pure-Go code.

Why this matters in Docker
Because the binary needs nothing else, a Go service can ship in a container built FROM scratch or a tiny distroless image — often 10–20 MB instead of hundreds. That small, fast-starting image is one of the main reasons Kubernetes-era teams picked Go. Module 12 builds one.
./... means "this folder and every folder below it".
CommandWhat it does
go mod init <path>Create go.mod and start a module
go run .Compile and run the current package (no binary kept)
go buildCompile to an executable
go fmt ./...Format every file in the module (runs gofmt)
go vet ./...Report suspicious code the compiler allows
go test ./...Run tests (Module 09)
go get pkg@versionAdd or upgrade a dependency
go mod tidyAdd missing and remove unused dependencies in go.mod
go doc fmt.PrintlnShow documentation in the terminal
06

gofmt and go vet

gofmt rewrites your source into the one official Go style: tabs for indentation, aligned comments, sorted imports, standard spacing. There are no options to argue about, so every Go codebase in the world looks the same — reading a stranger's code feels like reading your own. Run go fmt ./..., or let your editor do it on save. Code reviews in Go teams simply reject unformatted code.

bashterminal
gofmt -l .          # list files that are not formatted
gofmt -d main.go    # show the diff gofmt would apply
go fmt ./...        # rewrite files in place
go vet ./...        # find likely bugs

go vet goes further: it catches code that compiles but is almost certainly wrong, like a Printf verb that does not match its argument. The program below compiles and runs, but vet flags it.

gomain.go
package main

import "fmt"

func main() {
	name := "Gopher"
	age := 14
	fmt.Printf("%s is %d years old\n", name, age)
	// go vet would flag the next line: %d given a string
	fmt.Printf("%d\n", name)
}
Outputcompiled & run with real Go
Gopher is 14 years old
%!d(string=Gopher)

When a verb does not match, fmt prints %!d(string=Gopher) instead of crashing. go vet reports: fmt.Printf format %d has arg name of wrong type string.

Run vet in CI
go test already runs a subset of vet checks automatically. Most teams also add staticcheck or golangci-lint in CI for deeper linting.
07

How this handbook works

Go does not run inside a browser tab, so this handbook does not pretend to. Instead, every example block is a complete program plus the exact output it prints — and every one was compiled and run with the real Go toolchain before it was published. If the page says a program prints 42, the program printed 42.

  1. 1
    Read the example

    Predict the output before you look at it. Guessing wrong is where the learning happens.

  2. 2
    Copy it into your editor

    Save it as main.go in a module folder and run go run main.go. Every example is self-contained and uses only the standard library.

  3. 3
    Do the "Your turn" task

    Each example has a small change to make. Change it, predict, run.

  4. 4
    Read the error cards

    Every red card is a real compiler or runtime message from Go, with why it happens and the fix. You will see these same messages in your own terminal.

  5. 5
    Use the floating board

    Terms, key ideas and your progress for the module are collected on the floating board as you read.

  6. 6
    Take the exam

    After the modules, the 25-question Go certification exam gives you a certificate at 70% or more.

Using AI to learn Go without cheating yourself
AI assistants write passable Go. That is exactly why you should not let them write it for you while you learn. Use AI to explain a compiler error you have already read, to quiz you ("give me five questions on slices"), or to review code you wrote. Do not paste an exercise and copy the answer — in an interview there is no assistant, and questions like "what does this slice code print?" are designed to find people who never traced it themselves.
Module
A Go project: a folder tree with a go.mod file that names it and pins its dependencies. Created with go mod init.
Package
A folder of .go files that share one package name. The unit of compilation and of visibility.
package main
The special package that compiles to an executable; it must contain func main().
Exported name
A name starting with an upper-case letter, visible to other packages.
Static binary
An executable that contains everything it needs (your code, libraries, the Go runtime), so it runs without installing anything else.
gofmt
The official Go formatter. Its output is the one accepted Go style.
go vet
A tool that reports code that compiles but is likely wrong, such as mismatched Printf verbs.
Quick check

You run go build on a pure-Go web service and copy the binary to a fresh Linux server of the same architecture. What else must be installed there for it to run?

Every lesson in the handbook

17 modules · 134 lessons · each one ticks itself when you reach the end.

00Getting Started0 / 7
01Fundamentals0 / 7
02Flow Control0 / 5
03Functions0 / 8
04Arrays, Slices & Maps0 / 7
05Structs & Methods0 / 7
06Interfaces0 / 7
07Error Handling0 / 6
08Goroutines & Channels0 / 7
09Packages, Modules & Testing0 / 7
10Generics0 / 6
11Errors & Debugging0 / 8
12Go + Tools0 / 9
13Data Structures & Algorithms0 / 13
14Problem Solving0 / 12
15Interview Questions0 / 12
16Job Ready0 / 6

Frequently asked questions

Is this Go handbook free?
Yes — every module, every example and the certification exam are free, with no signup and no paywall. The exam asks you to sign in with Google so the certificate can carry your name.
Do I need to know another programming language first?
No. Module 01 starts from variables and types and assumes nothing. If you already know another language you will move faster, and the handbook calls out where Go differs: no classes or inheritance, no exceptions, errors returned as values, a single for loop, and unused variables and imports being compile errors.
Do I need to install anything?
Yes — the Go toolchain from go.dev/dl, and Module 00 shows how to install it and run your first program. The examples on this page do not run in the browser; instead, each example program was compiled and run with the real Go toolchain before publishing, and the output shown is exactly what it printed, so you can paste it into main.go, run go run main.go and get the same result. The labs in Module 12 need third-party modules such as Gin, pgx and go-redis, so they are shown as clearly marked snippets.
Which version of Go does this handbook use?
Go 1.22 or newer is the baseline, so loop variables are per-iteration and for i := range 10 works. Every example is verified on the current Go release, and newer features — the slices, maps and cmp packages, b.Loop in benchmarks, wg.Go — are marked with the version that added them. Older behaviour, such as the pre-1.22 loop-variable bug, is shown side by side where it still matters.
Is there a certificate?
Yes. Pass the 25-question exam (35 minutes) with 70% or more and generate a SolutionGigs Go certificate with your name, score, date and a certificate ID — download it, print it or add it to LinkedIn.
Is it Go or Golang?
The language is called Go. "Golang" comes from its original website, golang.org, and stuck because "go" is hard to search for. Both mean the same language — job posts use either.
Is Go good for beginners?
Yes. Go has very few keywords, one way to format code, one loop, and compiler errors that point at the exact line. The parts that take practice — pointers, interfaces and concurrency — are covered step by step in Modules 05, 06 and 08.
What do I need to run Go programs?
Only the Go toolchain from go.dev/dl (or brew/winget) and a text editor. VS Code with the Go extension or GoLand is recommended. There is no separate runtime to install on the machines where you deploy.

Finish the Go handbook, then get hired

Sit the exam for your certificate, run your resume through the ATS checker, and see the jobs that ask for exactly this.

Check my resume
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.