The go command builds, tests and runs code in one tool, and it is easy to skip a step and end up shipping a binary nobody rebuilt. This walkthrough creates a small module, formats it, tests it, then produces a named executable, entirely as an ordinary user. Allow about 15 minutes for the first run, including a possible module download.
You need a shell, a writable working directory, the Go toolchain, and network access only if the module needs to fetch dependencies. None of the steps below needs root. Do not use sudo for a project build or for go install.
Check which executable your shell will actually run before you start anything. A package-managed Go and a manually installed Go can both exist on the same machine, and they do not always agree.
$ command -v go
$ go version
$ go env GOROOT GOPATH GOMOD GOPROXY
The reference machine reports go version go1.22.2 linux/amd64 for /usr/bin/go. The installed go(1) manpage is dated 2022-03-15, so treat go help as the current source for flags. The GOMOD value is /dev/null outside a module. If the version or path is not what you expect, fix your PATH before continuing.
Work in a new directory so the generated files are easy to spot and remove later. The module path is just an identifier used by imports; it does not need to be a real hosted repository for a local example like this.
$ mkdir -p "$HOME/tmp/go-command-demo"
$ cd "$HOME/tmp/go-command-demo"
$ go mod init example.invalid/greeter
go: creating new go.mod: module example.invalid/greeter
go mod init writes go.mod and refuses to overwrite an existing one. Treat that file as source control material: review it, commit it with the program, and resist editing it casually just to silence a build error.
Create main.go with a deliberately small program. The redirection below changes project state, so check the target directory first if you are adapting this to an existing checkout.
$ test -f main.go && { printf '%s\n' 'main.go already exists; stop and inspect it' >&2; exit 1; }
$ printf '%s\n' \
'package main' \
'' \
'import "fmt"' \
'' \
'func main() {' \
' fmt.Println("hello from Go")' \
'}' > main.go
Verify the module and source are both present:
$ ls -l go.mod main.go
$ go list -m
example.invalid/greeter
Run the formatter before reviewing anything else. go fmt invokes gofmt -l -w on the selected packages and prints the files it changes. Using . makes the intended package explicit instead of relying on the current-directory default.
$ go fmt ./
main.go
$ go run .
hello from Go
go run compiles a temporary executable, runs it, and does not leave the binary behind in your project directory. Its exit status reflects the go command, not necessarily your program, so reach for go build when you need something you can check separately.
There are no test files in this tiny example, but the command still checks that the package builds. In a real project, go test ./... walks every package in the module and runs the files ending in _test.go.
$ go test ./...
? example.invalid/greeter [no test files]
Tip: a cached result is not a failure. (cached) just means the inputs and flags matched an earlier run; use go test -count=1 ./... when you need to force a fresh one. Run go vet ./... separately if you want its diagnostics on their own.
Build into a project-local output directory so the result cannot land on top of a system executable. The -o flag chooses the output path.
$ mkdir -p bin
$ go build -o bin/greeter .
$ ./bin/greeter
hello from Go
$ file bin/greeter
bin/greeter: ELF 64-bit LSB pie executable
The exact file description varies by platform and build settings; what matters is that the file exists, is executable, and prints the expected line. go build compiles packages and their dependencies but does not install them anywhere.
Importing a package outside the standard library can make module-aware commands update go.mod and go.sum. Review those changes, and the dependency's source and licence, before accepting them. go mod tidy adds missing modules and removes unused requirements, so run it only once you understand the dependency graph it is about to change.
go get changes the current module's dependency requirements; it is not a general install command. For a command published as a versioned module, go install example.com/tool/cmd/[email protected] installs its executable into GOBIN, or normally GOPATH/bin, without touching the current module. Prefer an explicit version over @latest when repeatability matters, and check the destination with go env GOBIN GOPATH.
Warning: installation here is a user-level change. If a build instruction tells you to write under /usr/local/bin, stop and check ownership, provenance and rollback first: a privileged copy hands every user on the box an unreviewed binary. Undo a user-level install by removing the exact executable from the reported GOBIN or GOPATH/bin directory, and never remove a shared executable just because one project build failed.
command -v go and go version must agree with the toolchain you actually intend to use. Fix the shell environment rather than mixing files from several versions.go.mod. Run go env GOMOD and change to the module root.go.mod, go.sum and GOPROXY. A clean build is not proof that a dependency is trustworthy.go build -o bin/name . and review git diff before committing, and avoid writing over a path an administrator or service already owns.(cached) is normal; use -count=1 to force execution, then look into any result that changes.go version matched the executable you intended to use.go.mod and your source sit in the intended module.go fmt ./..., go test ./... and go vet ./... complete successfully.go build -o bin/greeter . produced the expected executable.