Installing and Running Go

Updated

September 13, 2026

Installing and Running Go

The boring way to get Go is the official toolchain from go.dev/dl. One go binary on your PATH, Go 1.27, modules on by default, and the editor you already use. This chapter stops at a module you can run and a binary you can keep.

Mental model

Go is compiled. The go command is the compiler, linker, module manager, and test runner. You install one toolchain. Each module pins a language version in go.mod. With GOTOOLCHAIN=auto (the default), go may download a matching compiler. With GOTOOLCHAIN=local, it uses only what you installed.

GOPATH still names a cache and an install directory (pkg/mod, bin). It is not where new code lives. New code lives in a directory that has a go.mod.

A terminal is the window where you type commands. PATH is the list of directories the shell searches for a program named go. A file path is a location on disk (main.go, /home/you/desk). Put the directory that contains the go binary on PATH so go version works from any folder.

Worked examples

Case 1: Prove the toolchain is on PATH

Install from go.dev/dl — the official site, not a random script. Follow that page for your OS. Then:

go version

Output (OS and architecture match your machine):

go version go1.27.0 linux/amd64

Anything that starts with go version go1.27 is fine. If the shell says the command is not found, PATH does not include the directory that holds go.

This program prints the same facts from inside a running binary:

// where.go
package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Println(runtime.Version())
    fmt.Println(runtime.GOOS + "/" + runtime.GOARCH)
}

Run:

go run where.go

Output (again, OS/arch follow the machine):

go1.27.0
linux/amd64

go run compiles a temporary executable and runs it. There is no interpreter mode.

Case 2: Ask the toolchain about itself

go env GOROOT GOPATH GOMODCACHE GOTOOLCHAIN GO111MODULE

Typical output:

/usr/local/go
/home/you/go
/home/you/go/pkg/mod
auto
on
Variable Meaning
GOROOT Installed toolchain
GOPATH Cache root: module zip cache under pkg/mod, go install binaries under bin
GOMODCACHE Downloaded modules
GOTOOLCHAIN auto may fetch a compiler to match go.mod; local uses only the install
GO111MODULE on — modules are the default. Do not turn this off.

You do not create $GOPATH/src/... trees for new work.

A go.mod can also name a toolchain. The go line is the language version. The optional toolchain line is which compiler auto should prefer:

module desk

go 1.27

toolchain go1.27.0

Leave GOTOOLCHAIN=auto unless you are debugging the compiler itself.

Case 3: First module

Pick an empty directory. Create the module metadata, then the program.

mkdir desk
cd desk
go mod init desk

That writes go.mod:

module desk

go 1.27

Save as main.go:

// main.go
package main

import "fmt"

func main() {
    fmt.Println("desk module is running")
}

Run:

go run .

Output:

desk module is running

The . means “the package in this directory.” That is the habit to keep. go run main.go works for a single file; go run . is what you want once the folder is a module.

Case 4: Build a binary you can keep

Same module, same go.mod. Replace main.go with this complete program:

// main.go
package main

import "fmt"

func main() {
    fmt.Println("shift board ready")
}

Run:

go build -o desk .
./desk

Output:

shift board ready

go build -o desk . writes an executable named desk in the current directory. There is no VM to install on the machine that runs it (this book does not use cgo). Rebuild after you change the source; an old binary will not update itself.

Use whatever editor you already like. A language server (gopls) is optional polish. This book never assumes a particular IDE. gofmt is not optional; the editor is.

The trap

Installing Go from a distro package that lags a year, from a random curl | bash, or from a tutorial that sets GO111MODULE=off and dumps code in $GOPATH/src. The first file still runs. The project does not exist yet.

This program is fine. The layout around it is the bug: no go.mod.

// orphan.go
package main

import "fmt"

func main() {
    fmt.Println("I have no module")
}

Run:

go run orphan.go

Output:

I have no module

Single-file go run still compiles stdlib-only files outside a module. That convenience hides the missing go.mod. The moment you add a second package or a dependency, the folder is not a project. Run go mod init desk before the second file exists.

The same class of mistake: setting GO111MODULE=off, or pinning GOTOOLCHAIN to an older compiler “to match a blog post.” Pin go 1.27 in go.mod. Install 1.27 from go.dev.

The boring rule

  • Install from go.dev/dl. Confirm with go version.
  • New work starts with go mod init.
  • Use go run . and go build -o <name> . from the module root.
  • Leave GOPATH alone. Do not set GO111MODULE=off.
  • GOTOOLCHAIN=auto is fine. The go line in go.mod is the language pin.
  • The editor is yours. Format with gofmt.

Try this

  1. Run go env GOVERSION GOTOOLCHAIN. Then GOTOOLCHAIN=local go env GOTOOLCHAIN and confirm it prints local.
  2. In the desk module, change the printed string and run go build -o desk . again. Run ./desk and confirm it is the new text, not a stale binary.
  3. From desk/, run go env GOMOD. It should print the full path to go.mod. From your home directory, run it again and notice it is empty (or /dev/null).