Guides

How to install Go (Golang) on Linux and Windows, and use go install

Install Go the official way: the go.dev tarball in /usr/local/go plus PATH, apt or snap, the Windows MSI, then go install, GOBIN and cross-compiling.

Published ~10 min read
On this page

Short answer: download the archive for your system from go.dev/dl, delete any old /usr/local/go, unpack the new one with sudo tar -C /usr/local -xzf and add /usr/local/go/bin to your PATH. go version confirms it. On Windows, run the MSI from the same page. As of October 2026 the current release is Go 1.27.3.

Linux, x86-64 · example
curl -LO https://go.dev/dl/go1.27.3.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.27.3.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
source ~/.profile
go version
go version go1.27.3 linux/amd64

The builds, go install, cross-compiling and error messages on this page were run on Debian 12 with Go 1.26.0 (linux/amd64) in a scratch directory on 21 October 2026, with downloads switched off. The install steps follow go.dev/doc/install; version numbers come from go.dev/dl and the Go release history, read the same day.

Which way should you install Go?

MethodVersion you getUpdatesGood for
Official archive from go.dev/dl1.27.3 (or 1.26.10)By hand, same steps againServers and development machines: the default
apt: golang-goDebian 12: 1.19 (1.23 in backports) · Debian 13: 1.24 · Ubuntu 22.04: 1.18 · Ubuntu 24.04: 1.22With apt, within that versionBuilding Debian or Ubuntu packages, old projects
snap: go --classic1.27.3, published by CanonicalAutomaticUbuntu machines that already use snaps
Windows MSI from go.dev/dl1.27.3Run the newer MSIWindows 10, 11 and Windows Server
winget: GoLang.GoWhatever the manifest holdswinget upgradeWindows with winget

Go ships two major releases a year: 1.25 in August 2025, 1.26 in February 2026 and 1.27 in August 2026. Each is supported until two newer ones exist, so as of October 2026 only 1.27 and 1.26 get fixes from the Go team, and every distribution package in the table is older than that (distributions may backport security fixes on their own). To get the newest version number in a script:

any Linux
curl -s 'https://go.dev/VERSION?m=text' | head -n 1
go1.27.3

How do I install Go on Linux?

  1. 1Pick the right archive

    uname -m prints x86_64 for linux-amd64 archives and aarch64 for linux-arm64. The download page on go.dev lists a SHA-256 checksum next to each file; compare it with sha256sum go1.27.3.linux-amd64.tar.gz.

  2. 2Remove the old tree, unpack the new one
    shell
    sudo rm -rf /usr/local/go
    sudo tar -C /usr/local -xzf go1.27.3.linux-amd64.tar.gz

    The Go documentation is explicit: do not unpack a new archive into an existing /usr/local/go, it is known to produce broken installations. Updating later means repeating exactly this step with the newer file.

  3. 3Put Go on your PATH
    ~/.profile (one user) or /etc/profile.d/go.sh (everyone)
    export PATH=$PATH:/usr/local/go/bin
    export PATH="$PATH:$(go env GOPATH)/bin"     # tools from go install, ~/go/bin by default

    The profile is read at login, so run source ~/.profile or log in again. How the different startup files relate is in setting environment variables on Linux.

  4. 4Check it
    shell
    go version
    go env GOROOT GOPATH

One trap on servers: sudo go build fails with sudo: go: command not found, because sudo replaces your PATH with its own secure_path, which does not contain /usr/local/go/bin; in our test a shell with Debian’s default sudo path could not find go either. Build as your normal user instead; only installing the result needs root.

apt and snap: quicker, but older or different

Debian · Ubuntu
sudo apt install golang-go                          # the distribution's Go
sudo apt install -t bookworm-backports golang-go    # Debian 12, backports enabled: 1.23
sudo snap install go --classic                      # Ubuntu, current Go

An old Go matters more than it seems. Since Go 1.21, go.mod files can carry a three-part version such as go 1.25.0, and new ones written by a recent Go do. Go 1.19 or 1.18 cannot even parse that:

Example output, Go 1.19 on a current project
go: errors parsing go.mod:
/home/you/app/go.mod:3: invalid go version '1.25.0': must match format 1.23

Go 1.21 and later handle it differently: when a module asks for a newer Go, the go command downloads that toolchain into the module cache and uses it. That is convenient, but it means your installed Go quietly runs another version. Some distribution builds change that default, so check with go env GOTOOLCHAIN. With GOTOOLCHAIN=local it refuses instead, which is what we got on Go 1.26.0 with a go.mod asking for 1.27.0:

Output on Debian 12, Go 1.26.0
go: go.mod requires go >= 1.27.0 (running go 1.26.0; GOTOOLCHAIN=local)

How do I install Go on Windows?

Download go1.27.3.windows-amd64.msi from go.dev/dl and run it. By default it installs into Program Files and adds Go to the PATH; close and reopen every terminal, then check:

PowerShell or Command Prompt · example
go version
go version go1.27.3 windows/amd64

# unattended, as Administrator
msiexec /i go1.27.3.windows-amd64.msi /qn

# or with winget
winget install --id GoLang.Go -e

Windows Server 2022 and 2019 have no winget out of the box; see winget on Windows Server, or simply use the MSI.

Your first program: go mod init, go run, go build

Output on Debian 12, Go 1.26.0
$ mkdir hello && cd hello
$ go mod init example.com/hello
go: creating new go.mod: module example.com/hello
$ cat go.mod
module example.com/hello

go 1.25.0

Every Go project is a module, and go mod init starts one. The module path is a name, not a download: example.com/hello is fine locally, a repository path such as github.com/you/hello is the convention for published code. Note the go 1.25.0 line: Go 1.26 writes the previous release into new modules. Now the program:

main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello from Go")
}
Output on Debian 12, Go 1.26.0
$ go run .
Hello from Go
$ go build -o hello .
$ ls -l hello
-rwxr-xr-x 1 root root 2392561 Oct 21 22:54 hello
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=…, with debug_info, not stripped

go run compiles into a temporary directory and runs the result; go build leaves a single 2.4 MB executable that needs no Go installation on the machine that runs it. go vet ./... and gofmt -l . both came back clean on this program. Dependencies are added with go get example.org/pkg@latest, and go mod tidy prunes what the code no longer imports. The shell tools used here (file, ls -l, uname) are covered in the Linux commands cheat sheet.

go install, GOPATH and GOBIN

go install builds a program and puts the binary into a bin directory instead of the current one. For a tool from the internet, name a version:

shell
go install golang.org/x/tools/gopls@latest
go env GOPATH GOBIN
ls "$(go env GOPATH)/bin"
  • Where the binary goes: $GOBIN if it is set, otherwise $(go env GOPATH)/bin, which is ~/go/bin by default. In our test, go install . put hello into GOPATH/bin, and with GOBIN set it went there instead.
  • Make it permanent: go env -w GOBIN=$HOME/.local/bin writes the setting to Go’s own environment file (go env GOENV shows where).
  • go get no longer installs programs. It only edits go.mod.
Output on Debian 12, Go 1.26.0, outside a module
$ go install golang.org/x/tools/gopls
go: 'go install' requires a version when current directory is not in a module
	Try 'go install golang.org/x/tools/gopls@latest' to install the latest version
$ go get golang.org/x/tools/gopls@latest
go: go.mod file not found in current directory or any parent directory.
	'go get' is no longer supported outside a module.
	To build and install a command, use 'go install' with a version,
	like 'go install example.com/cmd@latest'

Cross-compiling with GOOS and GOARCH

Go builds for another system with two environment variables and no extra toolchain:

Output on Debian 12, Go 1.26.0
$ GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o web-arm64 .
$ file web-arm64
web-arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, …
$ GOOS=windows GOARCH=amd64 go build -o web.exe .
$ file web.exe
web.exe: PE32+ executable (console) x86-64, for MS Windows, 16 sections
$ go tool dist list | wc -l
47
TargetGOOSGOARCH
Linux server, Intel or AMDlinuxamd64
Linux on 64-bit ARM (ARM servers, Raspberry Pi 4 and 5 with a 64-bit OS)linuxarm64
Windows Server or Windows 10/11windowsamd64
Apple silicon Macdarwinarm64
FreeBSDfreebsdamd64

Cross-compiling switches cgo off by default, so code that needs C (for example the mattn/go-sqlite3 driver) needs a C cross-compiler as well. Run a binary built for the wrong architecture and the shell answers cannot execute binary file: Exec format error, which is what our arm64 build did on the x86-64 host.

A static binary for your server

A small web service shows why CGO_ENABLED=0 matters. It reads its address from an environment variable:

main.go
package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func main() {
	addr := os.Getenv("ADDR")
	if addr == "" {
		addr = "127.0.0.1:8080"
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "ok")
	})
	log.Printf("listening on %s", addr)
	log.Fatal(http.ListenAndServe(addr, nil))
}
Output on Debian 12, Go 1.26.0 (gcc installed)
$ go build -o web-default .
$ ldd web-default
	linux-vdso.so.1 (0x…)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x…)
	/lib64/ld-linux-x86-64.so.2 (0x…)
$ CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o web .
$ file web
web: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, …
$ ls -l web-default web
-rwxr-xr-x 1 root root 5755042 Oct 21 22:55 web
-rwxr-xr-x 1 root root 8423646 Oct 21 22:55 web-default

With a C compiler present, the net package uses cgo and the binary links against the system’s glibc. Copy that to an older distribution and it can fail with version 'GLIBC_2.34' not found, a case covered in error while loading shared libraries. CGO_ENABLED=0 gives a static binary that runs on any Linux of the same architecture. -trimpath removes your local paths, and -s -w drops the symbol table and debug data; together they took this binary from 8.4 to 5.8 MB. Panics still print function names and line numbers: a test program built this way showed main.boom(...) with its file and line in the trace. go version -m ./web lists the settings a binary was built with, CGO_ENABLED=0 included.

Run it as a systemd service

  1. 1Copy the binary and create a user
    shell
    scp web you@203.0.113.10:/tmp/web        # from your machine
    
    # on the server
    sudo useradd --system --no-create-home --shell /usr/sbin/nologin web
    sudo install -m 755 /tmp/web /usr/local/bin/web

    Use install, not cp, when you later replace the binary of a running service: on our Debian 12 test, cp over a running executable failed with Text file busy, while install (GNU coreutils 9.1) replaced it. More ways to move files are in transferring files to a VPS.

  2. 2Write the unit
    /etc/systemd/system/web.service
    [Unit]
    Description=Small web service written in Go
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    User=web
    Group=web
    Environment=ADDR=127.0.0.1:8080
    ExecStart=/usr/local/bin/web
    Restart=on-failure
    RestartSec=2
    NoNewPrivileges=yes
    ProtectSystem=strict
    ProtectHome=yes
    PrivateTmp=yes
    
    [Install]
    WantedBy=multi-user.target
  3. 3Start it and follow the log
    shell
    sudo systemctl daemon-reload
    sudo systemctl enable --now web
    journalctl -u web -f
    curl http://127.0.0.1:8080/

    The log.Printf line appears in the journal, and the curl should print ok. Every directive in the unit is explained in creating a systemd service.

Common Go install errors

MessageCauseFix
go: command not found/usr/local/go/bin is not on the PATH of this shellAdd it to ~/.profile, then source it or log in again
sudo: go: command not foundsudo uses secure_pathBuild without sudo, or call /usr/local/go/bin/go
go: go.mod file not found in current directory or any parent directoryNot inside a modulego mod init example.com/app
invalid go version '1.25.0': must match format 1.23Go older than 1.21, usually from aptInstall from go.dev/dl
go.mod requires go >= 1.27.0 (running go 1.26.0; GOTOOLCHAIN=local)The module needs a newer Go and downloads are offUpdate Go, or allow GOTOOLCHAIN=auto
cannot execute binary file: Exec format errorBuilt for another architectureRebuild with the right GOARCH
version 'GLIBC_2.34' not foundcgo binary built on a newer glibcCGO_ENABLED=0, or build on the oldest target

Go on a VPS

Because a Go program is one file, the easiest deployment is to build on your own machine or in CI with the right GOOS and GOARCH, copy the binary and restart the service. If you do build on the server, keep an eye on the disk: in our test, building two small programs for three targets left 340 MB in the build cache. Check it with du -sh $(go env GOCACHE) and clear it with go clean -cache; go clean -modcache removes downloaded modules. Builds use every core you give them, and our Standard KVM line puts more cores on each price step than Hi-CPU KVM, whose EPYC cores suit programs that lean on one or two threads. The finished binary of a typical API is happy on the smallest Standard KVM plan with 2 cores and 4 GB of RAM. The Linux VPS images for Ubuntu and Debian take the Linux commands on this page as written.

Frequently asked

Which Go version should I install?

The newest release from go.dev/dl, which was Go 1.27.3 as of October 2026. Each major Go release is supported until two newer majors exist, so 1.27 and 1.26 get fixes and older ones do not. Distribution packages lag behind: Ubuntu 24.04 ships Go 1.22 and Debian 12 ships 1.19, too old for many current projects.

Where does go install put the binary?

Into the directory in GOBIN if that is set, otherwise into the bin folder under GOPATH, which is ~/go/bin on Linux by default. Add that folder to your PATH, or set GOBIN permanently with 'go env -w GOBIN=$HOME/.local/bin'. Outside a module, go install needs a version, for example 'go install golang.org/x/tools/gopls@latest'.

How do I update Go on Linux?

Download the new archive from go.dev/dl, then run 'sudo rm -rf /usr/local/go' and 'sudo tar -C /usr/local -xzf' with the new file. Never unpack a new archive over an existing /usr/local/go, which the Go documentation says produces broken installations. 'go version' confirms the update; your PATH stays the same.

How do I uninstall Go?

Run 'go clean -cache -modcache' first to remove the build and module caches, then delete /usr/local/go with 'sudo rm -rf /usr/local/go', remove the PATH line from ~/.profile or /etc/profile.d/go.sh, and delete ~/go if you no longer need its tools. On Windows, uninstall Go under Settings, Apps.

Related articles

All guides