File types in a Go source tree¶
Source files the go tool recognizes¶
| Filename pattern | What it means |
|---|---|
foo.go |
Ordinary source file. Compiled into the package. |
foo_test.go |
Test file. Compiled only by go test, never in normal builds. |
foo_linux.go |
Implicit build constraint: only compiled when GOOS=linux. |
foo_amd64.go |
Only compiled when GOARCH=amd64. |
foo_linux_amd64.go |
Only compiled when both apply. |
foo_test_linux.go |
A test file restricted to linux. |
_foo.go, .foo.go |
Ignored entirely by the go tool. The leading _ or . is the off-switch. |
doc.go |
Convention only: a file holding the package-level doc comment. |
go.mod |
Module manifest. |
go.sum |
Module checksum database / lockfile. |
go.work, go.work.sum |
Workspace file for multi-module development. |
Anatomy of a .go source file¶
Every Go source file follows the same skeleton:
// Package greet provides a friendly greeting.
package greet // 1. package clause — required, first non-comment line
import ( // 2. imports
"fmt"
"strings"
)
const Exclamation = "!" // 3. top-level declarations
// (const, var, type, func — any order)
// Hello returns a greeting for name.
func Hello(name string) string {
name = strings.TrimSpace(name)
return fmt.Sprintf("Hello, %s%s", name, Exclamation)
}
Two non-obvious rules:
- Capitalization controls visibility. Identifiers starting with an uppercase letter are exported from the package; lowercase ones are package-private. There is no
public/privatekeyword — the compiler enforces this purely from the name. - Unused imports and unused local variables are compile errors, not warnings. This is enforced rigorously.
Build constraints¶
Build constraints decide whether a file is included in a build.
Explicit constraints (//go:build)¶
Rules:
- The
//go:buildline must appear before thepackageclause, preceded only by blank lines and other comments. - It must be followed by a blank line to distinguish it from the package doc comment.
- At most one
//go:buildline per file. - The expression uses boolean operators:
||,&&,!, and parentheses.
Implicit constraints from filenames¶
These constraints come from filename suffixes — no comment needed.
server_linux.go→ effective constraint//go:build linuxmath_amd64.go→//go:build amd64utils_windows_386.go→//go:build windows && 386
Automatically satisfied tags¶
During any build, these tags are true:
- The current
GOOS(e.g.linux,darwin,windows). - The current
GOARCH(e.g.amd64,arm64). - The
unixtag, on any Unix-like OS. - The compiler in use:
gcorgccgo. cgo, if cgo is enabled.- A tag for every Go version up to the current one:
go1.1,go1.21,go1.22, ... - Any custom tags passed via
-tagsto thegocommand.
Test files — two flavors¶
A test file can declare the same package it tests, or a separate _test package.
// foo_test.go — internal test (can see unexported identifiers)
package foo
import "testing"
func TestAdd(t *testing.T) {
if got := add(2, 3); got != 5 {
t.Errorf("add(2,3) = %d; want 5", got)
}
}
// foo_test.go — external test (tests the public API only)
package foo_test
import (
"testing"
"example.com/foo"
)
func TestPublic(t *testing.T) { /* ... */ }
A package can have both. Test files can also define:
BenchmarkXxx(b *testing.B)— performance benchmarks.FuzzXxx(f *testing.F)— fuzz tests.ExampleXxx()— runnable examples that double as documentation.
go.mod — what each directive looks like¶
A go.mod is a line-oriented, UTF-8 text file. A full example with every directive:
module example.com/myapp
go 1.23.0
toolchain go1.23.4
require (
github.com/gorilla/mux v1.8.1
golang.org/x/crypto v0.21.0 // indirect
)
exclude github.com/some/pkg v1.4.0
replace github.com/some/pkg => ../local/pkg
retract v1.0.1 // do not depend on this version of MY module
godebug panicnil=1
| Directive | Purpose |
|---|---|
module |
The module's canonical import path. Exactly once. |
go |
Minimum Go language version this module requires. |
toolchain |
Suggested toolchain version for development and CI. |
require |
A dependency at a specific minimum version. // indirect marks transitive deps. |
exclude |
Refuse a specific version of a dependency. |
replace |
Redirect a module to a local path or to a fork. |
retract |
Mark versions of your own module as do-not-use. |
godebug |
Pin a GODEBUG toggle when this module is the main one. |
tool |
Declare a Go tool runnable via go tool. |
Do not hand-edit go.mod for routine changes. Use go get, go mod tidy, etc. — they are aware of go.sum and will keep both consistent.
go.sum — what it looks like¶
Two lines per (module, version) pair:
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
- First line: hash of the whole module zip.
- Second line: hash of only that module's
go.modfile.
The second line lets Go verify transitive metadata without downloading those modules. Both lines are written and checked by the go command automatically. Never hand-edit go.sum.