---
title: "What Happens Before main() in Go"
date: 2024-12-13
tags: ["go"]
description: "What the Go runtime does before main(): package init order, init functions, and startup orchestration."
---

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

```mermaid
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 return
```

### Package Dependency Ordering

Go initializes packages in dependency order, not import order. Leaf packages initialize first.

```mermaid
graph TD
    main["main\n(init last)"]
    A["Package A"]
    B["Package B"]
    C["Package C"]
    main --> A
    main --> B
    A --> C
```

Init 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.Once` when you need lazy or guarded initialization of shared resources. It's safer than relying on `init()` ordering.

### Exiting with os.Exit()

`os.Exit()` terminates the program immediately. No deferred functions run.

```go
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.
