SyntaxStudy
Sign Up
Go The init Function and Package Initialisation
Go Beginner 1 min read

The init Function and Package Initialisation

Each Go package can define one or more `init` functions. These functions run automatically before `main` when the program starts, after all variable declarations in the package have been evaluated. `init` functions cannot be called explicitly and take no arguments and return no values. They are primarily used for registering drivers, setting up package-level state, or validating configuration. Package initialisation order is deterministic within a package: variables are initialised in declaration order, and `init` functions run after all variables are initialised. Across packages, a package is initialised only after all of its imported packages have been initialised. The `main` package is always initialised last. The blank import (`import _ "pkg"`) imports a package solely for its side effects — specifically its `init` functions. This pattern is widely used to register database drivers (e.g., `import _ "github.com/lib/pq"` to register the PostgreSQL driver with `database/sql`) and image format handlers without using the package's exported identifiers directly.
Example
package main

import (
    "database/sql"
    "fmt"
    "log"
    "sync"

    // Blank import: registers the sqlite3 driver via its init() function.
    // The main package never uses the "mattn/go-sqlite3" identifier directly.
    _ "github.com/mattn/go-sqlite3"
)

// Package-level registry populated by init functions.
var (
    plugins   map[string]func() string
    pluginsMu sync.Mutex
)

func registerPlugin(name string, fn func() string) {
    pluginsMu.Lock()
    defer pluginsMu.Unlock()
    if plugins == nil {
        plugins = make(map[string]func() string)
    }
    plugins[name] = fn
}

// init runs before main, after package-level vars are initialised.
func init() {
    registerPlugin("greeter", func() string { return "Hello from greeter!" })
    registerPlugin("farewell", func() string { return "Goodbye from farewell!" })
    fmt.Println("init: plugins registered")
}

func main() {
    fmt.Println("main: starting")

    for name, fn := range plugins {
        fmt.Printf("plugin %q says: %s\n", name, fn())
    }

    // The blank-imported driver is now available to database/sql
    db, err := sql.Open("sqlite3", ":memory:")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    if err := db.Ping(); err != nil {
        log.Fatal(err)
    }
    fmt.Println("SQLite3 in-memory DB connected successfully")
}