The underscore in front of an import statement is solely for its side-effects.
An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers. To import a package solely for its side-effects (initialization), use theblankidentifier as explicit package name:
import _ "lib/math"
When should we use underscore for import in Golang
Underscore is a special character in Go which acts as null container. Since we are importing a package but not using it, Go compiler will complain about it. To avoid that, we are storing reference of that package into _ and Go compiler will simply ignore it. Aliasing a package with an underscore which seems to do nothing is quite useful sometimes when you want to initialize a package but not use it.
Fixing imported but not used
We can use a blank identifier(_) before the package name that will not be used as following code:
package main
import (
"fmt"
_ "math"
)
func main() {
name := "GoLinuxCloud"
age := 1
fmt.Println("My name is:", name, "and my age is:", age)
}
Fixing declared but not used
In the below code, two variables pageandauthorare declared
butauthor was not used. To avoid compile error, you have to assign
the variable to a blank identifier (_) as the code shown below:
package main
import (
"fmt"
)
func main() {
page := "GolinuCloud"
author := "Anonymous Author"
fmt.Println("Name is:", page)
_ = author
}
Output:
Page is: GolinuCloud
Fixing imported but not used
In the example below, we will import the math package but not use it at all.
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println("This is an example of importing packages in Golang!")
}
Output:
$ go run underscore.go
# command-line-arguments
./underscore.go:5:2: imported and not used: "math"
An unused import like math in the previous example should eventually be used or removed: blank assignments identify code as a work in progress.
package main
import (
"fmt"
_ "math"
)
func main() {
fmt.Println("This is an example of importing packages in Golang!")
}
Output:
This is an example of importing packages in Golang!
But sometimes it is useful to import a package only for its side effects, without any explicit use. For example, in the article working with SQLite3 in Golang, we import but not use the go-sqlite3 package:
import (
"database/sql"
"fmt"
"log"
_ "github.com/mattn/go-sqlite3"
)
_ "github.com/mattn/go-sqlite3": If a package is imported with a blank
identifier, the package’s init function is called:
func init() {
if driverName != "" {
sql.Register(driverName, &SQLiteDriver{})
}
}
Once it’s registered in this way, sqlite3 can be used with the standard
library’s sqlinterface in your code like in the example:
db, err := sql.Open("sqlite3", ":memory:")
Summary
underscore in front of an import statement means: create package-level
variables and execute the init function of that specific packages. And
(if applicable) the hierarchy of package-level variables and init
functions of packages imported by this package.
The only thing a package can do without being called is create
package-level variables (public or private) and run its init function.
References
https://go.dev/doc/effective_go#blank_import
https://go.dev/ref/spec#Import_declarations


