ProgrammingGo Developer

How does package initialization work in Go and what unexpected effects can occur from improper organization of init functions?

Pass interviews with Hintsage AI assistant

Answer

When a Go application starts, all non-test packages are initialized in a strict order: first, all imported dependencies are initialized (in chain), then the package itself is initialized. The following are used for initialization:

  • package-level variables (initialized top to bottom in the file)
  • init() functions (there can be multiple per package)

The init functions are called after the package variables are initialized. If a package is imported, its init is executed once before the variables/functions of that package are used.

Example:

var a = getA() func getA() int { fmt.Println("getA called") return 42 } func init() { fmt.Println("init called") } // Output: // getA called // init called

Features:

  • The order of initialization can become critical if variables from one package depend on variables from another imported package.
  • Multiple init() functions in one file or package are executed in the order they appear in the source code.
  • The main package is initialized last.

Trick Question

Can you explicitly call the init function of any package?

Answer: No, the init function is never called directly from the program code. It is called only by the runtime during the package initialization process at a predetermined moment, explicit calls to init() are not allowed — this will result in a compilation error.

Examples of real errors due to ignorance of nuances


Story

In the project, two packages imported each other to initialize global variables via init(). This led to cyclic dependencies and build errors — Go could not determine the correct order of initialization.


Story

A complex bug was caused by init functions using package global variables that had not yet been initialized. The result: ambiguous behavior at runtime with unpredictable states.


Story

In the project, a package was imported for side effects without explicit use (via import _ "some/lib"). After code reorganization, the init function of the required package was called too early (before the dependent variables in another package were initialized), leading to a hard-to-debug bug.