Go organizes code into packages. A package is a collection of source files in the same directory that share a package declaration. Most packages are libraries—they export functions and types for other code to use.
package main is different. It tells the Go compiler to produce an executable binary instead of a package archive.
package main
import "fmt"
func main() {
fmt.Println("Hello, World")
}
When you run go build on this file, you get an executable. Change package main to package hello, and go build produces nothing—the compiler expects a main package for executables.
The main Function
Inside package main, you need a main function. This is the entry point:
func main() {
// Program starts here
}
The main function takes no arguments and returns nothing. If you need command-line arguments, use os.Args. If you need to signal an error exit, use os.Exit(1).
The program terminates when main returns or when something calls os.Exit or log.Fatal.
Why package main Is Special
The Go toolchain has special behavior for package main:
-
go buildproduces an executable named after the directory or specified with-o -
go runcompiles and runs the program in one step -
go installplaces the executable in$GOPATH/binor$GOBIN
For other packages, go build compiles them but doesn't produce output unless they're being built as dependencies. go install places the compiled package in the build cache for linking.
One main Package Per Binary
A Go project can have multiple main packages, but each must be in a separate directory. Each main package becomes a separate executable.
Common structure for a project with multiple binaries:
project/
cmd/
server/
main.go (package main)
client/
main.go (package main)
internal/
auth/
auth.go (package auth)
You'd build them separately:
go build ./cmd/server
go build ./cmd/client
This produces two executables: server and client.
Importing package main
You can't import package main. If you try, the compiler rejects it:
import "myproject/cmd/server" // Error: can't import main package
This is intentional. package main is for executables, not libraries. If code needs to be shared, move it to a separate package that both main and other packages can import.
Testing package main
Go's testing framework works with package main. You can write tests for functions in main:
// main.go
package main
func add(a, b int) int {
return a + b
}
func main() {
result := add(2, 3)
fmt.Println(result)
}
// main_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
result := add(2, 3)
if result != 5 {
t.Errorf("Expected 5, got %d", result)
}
}
Run tests with go test. The test file must also declare package main to access unexported functions.
The init Function
Packages can have init functions that run before main:
package main
import "fmt"
func init() {
fmt.Println("Initialization")
}
func main() {
fmt.Println("Main")
}
Output:
Initialization
Main
init runs automatically when the package is initialized. You can have multiple init functions in the same package—they run in the order they appear in the source.
Use init for setup that must happen before main (registering drivers, initializing global state). Avoid complex logic in init—it makes programs harder to understand and test.
Command-Line Arguments
The main function doesn't take arguments, but os.Args provides access to them:
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: program <name>")
os.Exit(1)
}
fmt.Println("Hello,", os.Args[1])
}
os.Args[0] is the program name. Arguments start at index 1.
For more complex argument parsing, use the flag package:
package main
import (
"flag"
"fmt"
)
func main() {
name := flag.String("name", "World", "name to greet")
flag.Parse()
fmt.Println("Hello,", *name)
}
Run with ./program -name=Alice.
Exit Codes
A successful program exits with code 0. For errors, use os.Exit:
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
os.Exit terminates immediately without running deferred functions. If cleanup is needed, use return from main for normal exits and reserve os.Exit for error paths.
When Not to Use package main
If you're writing a library that other Go code will import, don't use package main. Use a descriptive package name instead:
package httputil
func BuildURL(base, path string) string {
return base + "/" + path
}
Other code imports it:
import "myproject/httputil"
url := httputil.BuildURL("https://example.com", "api")
Libraries don't have a main function. They export functions and types for other packages to use.
Multiple Files in package main
A package main can span multiple files:
// main.go
package main
func main() {
greet("World")
}
// greet.go
package main
import "fmt"
func greet(name string) {
fmt.Println("Hello,", name)
}
As long as all files in the directory declare package main, they're part of the same package. Build with go build . and the compiler combines them into one executable.
Further Reading
The Go specification's section on program execution defines how package main and func main work.
Effective Go's chapter on package names explains naming conventions and when to use main vs library packages.
For structuring larger projects, see the Go project layout guide, which demonstrates how to organize cmd/, internal/, and pkg/ directories.
If package main is where your Go programs begin and you appreciate the simplicity of that entry point, our package main tee marks that starting point.
0 comments