What is the difference between go build, go run and go install for a main package?
answer
- three commands, three destinations
- one of them leaves nothing behind
- current directory versus a bin directory
- GOBIN, defaulting to GOPATH/bin
- name comes from the last path element
basics
~20 sgo build compiles a main package and writes the executable into the current directory. go run builds it to a temporary file, runs it, then deletes the binary. go install writes the executable into GOBIN, which defaults to GOPATH/bin.
solid answer
~50 sAll three compile the same code; they differ in what they do with the result. `go build ./cmd/api` links an executable and drops it in the directory you ran the command from, named after the last element of the package path — `api` — unless you override it with `-o`. `go run ./cmd/api` builds into a temporary directory, executes the binary immediately, and removes it afterwards, so nothing is left on disk; arguments after the package go to your program, not to the go command. `go install ./cmd/api` builds and then places the executable in `$GOBIN`, or `$GOPATH/bin` when GOBIN is unset, which on a default setup is `~/go/bin` — the directory you put on PATH so the tool is callable by name. Day to day: `go run` while iterating, `go build` to produce an artefact next to you, `go install` to make a command available on the machine.
code
text · 5 lines$ go build ./cmd/api # writes ./api in the current directory
$ go build -o bin/api ./cmd/api
$ go run ./cmd/api -port 8080 # temp binary, runs, then deleted
$ go install ./cmd/api # writes $GOBIN/api, else $GOPATH/bin/api
$ go env GOBIN GOPATHgo deeper
Be ready to say, without hesitating, where each of the three commands leaves the executable, and that the default name comes from the last element of the package path. Knowing GOBIN defaults to GOPATH/bin earns real credit here.
Explain the mechanics behind the destinations: the temporary build directory go run uses and deletes, why building several packages discards the executables, and how -o changes both name and location.
Show the operational side — which command belongs in a Makefile, a container build, a CI compile check and a developer's inner loop, and why a shipped artefact should come from go build rather than go run.
Own the convention for the team: one documented way to produce a binary, one documented destination, so build scripts, container images and onboarding docs do not each invent their own.
## The one thing they share `go build`, `go run` and `go install` all do the same compilation work: they resolve the packages you named, compile them and everything they import, and link a program. The interesting difference is entirely about **where the produced executable ends up**, and interviewers ask this early because a candidate who cannot say where the binary went cannot debug the next problem either. ## go build — an artefact in the current directory `go build ./cmd/api` writes the linked executable **into the directory you are standing in**, not into the package's directory. The file name is the last element of the package's import path, so `./cmd/api` produces `api` (and `api.exe` on Windows). `go build .` in a directory named `hello` produces `hello`. There are two special cases worth knowing: - **`-o` overrides the name and location.** `go build -o bin/api ./cmd/api` writes exactly that path. `-o` also accepts a directory, which is how you emit several commands at once. - **A non-main package produces no file at all.** `go build ./internal/store` compiles the package as a *check* that it builds and then discards the result. The same is true when you name several packages at once: the compile happens, the executables are thrown away. That is why `go build ./...` is a useful "does everything still compile" step and a useless way to get binaries. ## go run — build, execute, discard `go run ./cmd/api` links the program into a temporary directory, runs it, and deletes it when it exits. Nothing appears in your working tree. Two practical details: - Anything after the package path is passed **to your program**: `go run ./cmd/api -port 8080` gives `-port 8080` to `api`, not to the go command. Build flags must come before the package. - If you pass a file list rather than a package (`go run main.go`), you must list **every** file of that main package. Splitting a helper into `helper.go` and then running `go run main.go` fails with undefined-symbol errors; `go run .` avoids the whole class of mistake. `go run` is for the edit-run loop and for one-shot programs. It is not a deployment mechanism: there is no artefact afterwards to ship, sign or inspect. ## go install — put the command on the machine `go install ./cmd/api` builds and then **installs**: it copies the executable to `$GOBIN`. If `GOBIN` is empty, the destination is `$GOPATH/bin`, and if `GOPATH` is itself unset it defaults to `$HOME/go` — so on a stock machine the answer is `~/go/bin/api`. `go env GOBIN GOPATH` prints both values and is the first thing to run when a freshly installed tool is "not found": almost always the binary is exactly where the go command said, and that directory is simply not on PATH. Installing a **non-main** package is not how you publish a library. Go has no separate "install the library" step that other builds then consume; dependencies are resolved from modules and compiled from source, with compiled results kept in the build cache. The useful case for `go install` is a command. ## Choosing between them | You want | Command | |---|---| | To see the program run right now | `go run ./cmd/api` | | A file you can copy, container-COPY or hand to someone | `go build -o bin/api ./cmd/api` | | The command available by name on this machine | `go install ./cmd/api` | | To know only whether the tree compiles | `go build ./...` | ## The mistakes this question is really testing - Thinking `go run` leaves a binary behind, and hunting for it. - Expecting `go build` to place the executable next to its source in `cmd/api/`. - Expecting `go install` to write into the current directory, or `go build` to write into GOBIN. - Passing program flags before the package path in `go run`, so the go command tries to interpret them. - Being surprised that `go build ./...` in a multi-package repo produces no files. None of these are exotic. They are the everyday friction of the first week with Go, and being crisp about "which command puts what where" removes all of them at once.
- With GOBIN unset, where exactly does go install put the executable?In `$GOPATH/bin`. If GOPATH is unset too it defaults to `$HOME/go`, so the binary lands in `~/go/bin`. Run `go env GOBIN GOPATH` to see both values on the machine in front of you; when a just-installed tool reports "command not found", that directory is nearly always missing from PATH rather than the install having failed.
- What does go build do when you point it at a package that is not package main?It compiles the package and its dependencies purely as a check and writes no output file — there is nothing to link. The same happens when you name several packages at once, even if some are main. That is why `go build ./...` is a compile check, and `go install ./...` or `go build -o <dir>/ ./...` is how you actually keep executables.
- Why does go run main.go sometimes fail with undefined symbols when go run . works?The file-list form compiles only the files you list. If the main package is split across `main.go` and `helper.go`, running `go run main.go` leaves the helper out and the link fails on the missing identifiers. Naming the package instead — `go run .` or `go run ./cmd/api` — compiles every file in it and sidesteps the problem entirely.
Same oven, three plans for the cake: eat it on the spot and wash the tin, leave it on the counter, or put it in the pantry where everyone can reach it.
saying these in an interview costs you the question
- Claims go run leaves the compiled binary in the current directory
- Thinks go install writes the executable into the working directory
- Expects go build to place the binary next to its source files
- Believes go build ./... produces one executable per main package
- Puts program flags before the package path in go run