What Go is
Go is a compiled language created at Google with a deliberately small feature set: one kind of loop, no classes, no exceptions, and a formatter that ends arguments about style. Writing it feels plain and explicit — errors are returned as ordinary values and checked with an if, and the compiler refuses to build a program that has an unused variable or import. The reward is that Go code is easy to read months later, compiles quickly to a single executable, and handles many things at once with goroutines and channels.
Where Go is used
- Cloud infrastructure and DevOps tooling
- Docker, Kubernetes and Terraform are written in Go, as are many of the command-line tools used to operate them.
- Web servers and APIs
- The standard library's net/http package is enough to build a production HTTP server without a framework, which is why a lot of backend services are Go.
- Command-line tools
- A Go program compiles to one self-contained binary with no runtime to install, which makes it a natural fit for tools that have to run on someone else's machine.
- Network services and proxies
- Programs that hold a large number of connections open at once — proxies, load balancers, chat servers — lean on goroutines, which cost far less than operating-system threads.
- Databases and storage systems
- CockroachDB, etcd and Prometheus are written in Go; the pattern of a fast, concurrent, self-contained server suits that kind of software.
Your first Go program
Saved as hello.go. You can paste it straight into the playground to see it run.
package main
import "fmt"
func main() {
name := "Asha"
steps := 4
fmt.Println(name, "took", steps, "steps.")
fmt.Printf("Twice that is %d.\n", steps*2)
}What it prints
Asha took 4 steps.
Twice that is 8.- Line 1 says which package this file belongs to. A program that can be run on its own must be in
package main. - Line 3 imports fmt, the standard-library package for formatted printing. Go refuses to compile a file that imports something it does not use, so every import is there because it is needed.
- Line 5 begins main, the function every Go program starts in. The opening brace has to be on the same line as
func; putting it on the next line is a compile error, and gofmt would have moved it back anyway. - Lines 6 and 7 declare variables with
:=, which declares and assigns in one step and lets Go work out the type:namebecomes a string andstepsan int. The indentation is a tab because that is what gofmt uses. - Line 8 prints with Println, which takes any number of values, puts a single space between each of them and adds a newline at the end. That is why the output reads naturally without any spaces inside the quoted pieces.
- Line 9 uses Printf for formatted output:
%dis a placeholder for an integer, filled bysteps*2, and the\nat the end is needed because Printf does not add a newline for you.
Run Go on your own computer
Go's toolchain is one download containing the compiler, formatter, test runner and package manager, all behind a single go command. There is nothing else to install.
Install Go
Download the installer for your platform from go.dev/dl and run it. Linux users can use their distribution's package instead, but the version there is sometimes behind; the official download is a tar archive you unpack into /usr/local. Any release that is still supported works for everything on this site.
Check it works
Open a new terminal, because the installer edits your PATH and terminals that were already open may not see the change, then confirm the version prints.
Shellgo versionCreate a module
Make a folder for the program, move into it, and run this once. It writes a go.mod file that names the module. A single-file program does not strictly need one, but every Go project has one, and it becomes required the moment you import anything outside the standard library.
Shellgo mod init helloSave the file and run it
Save the program as hello.go in that folder and run it. go run compiles to a temporary location and runs the result in one step, so it feels like an interpreter even though it is not. To produce an executable you can keep or copy elsewhere, use go build instead, which writes a file named after the module.
Shellgo run .Format on save
Go has one official style and gofmt applies it. Run it by hand, or better, set your editor to run it on save: the Go extension for VS Code and the gopls language server do this automatically.
Shellgofmt -w hello.go
A learning order for Go
Stages, not a timetable. Each one exists because the next would not make sense without it, and how long each takes depends on how much you write.
Stage 1. Packages, printing and variables
- package main and func main
- fmt.Println and fmt.Printf
- var and :=
- int, float64, string and bool
- constants
Go's strictness shows up immediately — an unused variable stops the build — so the first stage is partly about learning to appreciate a compiler that says no.
Stage 2. Control flow and functions
- if, including the optional init statement
- the single for loop in its three forms
- switch
- functions with multiple return values
- defer
Multiple return values are the basis of Go's error handling, and the for loop is the only loop there is. Both are small ideas that shape everything written afterwards.
Stage 3. Slices, maps and structs
- arrays versus slices
- append and len
- maps
- range loops
- structs and methods
Slices are the everyday collection and have some non-obvious behaviour around sharing an underlying array. Structs with methods are how Go organises data without classes.
Stage 4. Errors and interfaces
- the error type and if err != nil
- errors.New and fmt.Errorf
- wrapping, errors.Is and errors.As
- interfaces and implicit satisfaction
- pointers and pointer receivers
Go's error handling is explicit and repetitive on purpose. Interfaces are satisfied without declaring it, which is unlike most languages and is what makes the standard library so easy to compose.
Stage 5. Concurrency
- goroutines
- channels
- select
- sync.WaitGroup and sync.Mutex
- context for cancellation
Concurrency is the reason many teams choose Go, and its tools are simple to start with and subtle to use well. Learn it after the basics, not before; a data race is much easier to understand once slices and pointers are second nature.
Stage 6. Tooling and a real project
- go test and table-driven tests
- modules and go get
- net/http, encoding/json and os
- go vet and the race detector
- structuring a multi-package project
Testing and the standard library are built in, so a first real project — an HTTP service or a command-line tool — needs almost nothing from outside the toolchain.
Mistakes beginners make in Go
- Declaring a variable and not using it
- Go stops the build with 'declared and not used: x'. It is not a warning you can ignore; the program will not compile. The same rule applies to imports, which fail with '"os" imported and not used'. Delete the variable, or assign it to the blank identifier _ while you are experimenting.
- Using := when you meant =
- Inside an if or a loop, err := doSomething() creates a new variable that shadows the outer err, so the outer one never changes and your error check silently looks at the wrong value. The compiler allows it. When a variable already exists in scope, assign with =; use := only to declare.
- Writing to a map that was never made
- Declaring var counts map[string]int gives you a nil map. Reading from it is fine and returns zero values, but writing to it panics with 'panic: assignment to entry in nil map'. Create the map with make(map[string]int) or a literal before writing. The same family of error, 'invalid memory address or nil pointer dereference', comes from calling a method through a nil pointer.
- Ignoring the error return
- result, _ := strconv.Atoi(text) compiles and quietly gives you 0 when text is not a number. Go does not force you to check errors; the convention is that you always do, immediately, with if err != nil. Throwing the error away is a common way for a Go program to hide a bug until much later.
- Assuming a slice is an independent copy
- b := a[1:3] shares the same underlying array as a, so writing to b changes a. Whether append allocates a fresh array depends on the slice's capacity, which can make the behaviour look random. Use copy when you need a slice that is genuinely separate.
Strengths and trade-offs
Where it is strong
- A small language you can hold in your head: the specification is short, there is usually one way to do something, and code written by strangers looks like your own.
- Quick compiles and a single static binary, so deploying a Go program means copying one file.
- Concurrency built into the language with goroutines and channels rather than bolted on as a library.
- The standard library covers HTTP servers, JSON, testing, cryptography and templating, so many programs need no third-party packages at all.
Where it is not
- Verbose error handling: if err != nil { return err } appears after almost every call, and there is no shorter form.
- Deliberately limited: no classes or inheritance, generics only since Go 1.18 and simpler than in most other languages, and no exceptions. People who like expressive type systems find it plain.
- Garbage collected, so it is not for kernels, firmware or code with hard latency limits, where C, C++ or Rust are used.
- Not the language for graphical desktop apps, mobile apps or code running in the browser; its home is servers and command-line tools.
Who Go is for
Go is a good choice for a beginner who wants to build servers, command-line tools or cloud infrastructure, and a good second language for anyone who already knows Python or JavaScript and wants static types and real concurrency without the weight of C++ or Rust. Its rigidity — the compiler rejecting unused variables, the single loop, the mandatory formatting — is a feature for learners, because there is little style to argue about and one clear way to write most things. Look elsewhere if you want to make games, mobile apps or web front-ends, or if you want a language that lets you express elaborate type relationships; Go asks you to write things out plainly instead.
Questions about learning Go
- Is Go a good first language?
- It can be, especially if you want to build things that run on servers. The syntax is small, the toolchain is one download, and the compiler's strictness catches mistakes early. What makes it slightly harder than Python as a first language is the amount of explicit error checking and the lack of an interactive prompt: you write a file and run it every time. If your interest is data, scripting or programming in general, Python first is the easier road; if your interest is backend systems, Go first is a reasonable choice.
- Why does the compiler refuse an unused variable or import?
- Because Go treats them as errors rather than warnings, on purpose: an unused variable is usually a mistake or a leftover, and an unused import slows the build and hides what the file depends on. The fix is to delete it or, while experimenting, assign the value to the blank identifier _. Editors that use gopls remove unused imports automatically when you save.
- Is Go the same thing as Golang?
- Yes. The language is called Go; 'golang' comes from the address of its original website, golang.org, which has since moved to go.dev, and the word survives because 'go' on its own is hard to search for. In writing, call it Go.
- Does Go have classes?
- No. Go has structs, which hold data, and methods, which are functions attached to a type. There is no inheritance; reuse comes from embedding one struct in another and from interfaces, which a type satisfies simply by having the right methods. People coming from Java or C# usually find this odd at first and then find it simpler.
The primary source
When this guide and the official documentation disagree, the documentation is right and we would like to hear about it.