notes
What Happens Before main() in Go
What the Go runtime does before main(): package init order, init functions, and startup orchestration.
On this page
When we first start with Go, the main function seems almost too simple. But before main even begins, the Go runtime orchestrates careful initialization of all imported packages, runs their init functions and ensures everything is in the right order.
Program Startup Sequence
sequenceDiagram
participant OS
participant Runtime
participant Packages
participant main
OS->>Runtime: Execute binary
Runtime->>Runtime: Bootstrap (scheduler, GC, memory)
Runtime->>Packages: Init packages in dependency order
Packages->>Packages: Run init() functions
Packages-->>Runtime: All packages initialized
Runtime->>main: Call main()
main->>main: Main goroutine runs
main-->>OS: os.Exit or returnPackage Dependency Ordering
Go initializes packages in dependency order, not import order. Leaf packages initialize first.
graph TD
main["main\n(init last)"]
A["Package A"]
B["Package B"]
C["Package C"]
main --> A
main --> B
A --> CInit order: C -> A -> B -> main.
Multiple init Functions
You can have multiple init functions. They run in order they appear. Go initializes packages in the order of their dependencies.
Use
sync.Oncewhen you need lazy or guarded initialization of shared resources. It’s safer than relying oninit()ordering.
Exiting with os.Exit()
os.Exit() terminates the program immediately. No deferred functions run.
func main() {
if err := doSomethingRisky(); err != nil {
cleanup()
os.Exit(1)
}
}The main Goroutine
The main function runs in a special goroutine. If main returns, the entire program exits – even if other goroutines are still working. Use sync.WaitGroup to wait for background goroutines.