In Go, nil is the zero value for pointers, slices, maps, channels, functions, and interfaces—it is related to what other languages call a null pointer, but the rules differ. People searching golang nil or golang check if nil usually need pointer checks, slice emptiness, optional structs via pointers, or interface edge cases. The sections below cover pointers (including errors), empty versus nil slices, maps and channels, why struct values are never nil, and the interface typed-nil trap. For returning and checking errors (non-nil error values), see returning errors in Go.
Tested with Go 1.24 on Linux.
Types whose zero value is nil
Only these kinds of values compare meaningfully to nil with == and !=: pointers (including unsafe.Pointer), slices, maps, channels, functions, and interfaces. Booleans, numbers, strings, arrays, and struct values have other zero values (false, 0, "", zeroed fields)—they are never nil themselves. The language spec on zero values spells out the defaults.
golang check if pointer is nil (golang null pointer)
For a pointer p, p == nil is the usual golang nil pointer check (what many people still describe as a golang null pointer check from C-style habits).
package main
import "fmt"
type Config struct{ Host string }
func main() {
var cfg *Config
alive := &Config{Host: "example.com"}
fmt.Println("cfg is nil:", cfg == nil)
fmt.Println("alive is nil:", alive == nil)
}You should see cfg is nil: true and alive is nil: false.
Errors and nil
The error interface follows the same idea: after _, err := strconv.Atoi("bad"), use if err != nil before using the result. The zero value for an error variable is nil; see Handle errors and the errors package.
check if slice is empty golang versus a nil slice
A nil slice has length 0, but a non-nil slice can also have length 0 ([]T{} or make([]T, 0)). For “no elements,” len(s) == 0 is the usual check if slice is empty golang pattern and is true for both cases. Use s == nil only when you care that the slice header itself is nil (for example JSON null versus [] sometimes matters at API boundaries).
package main
import "fmt"
func main() {
var a []int // nil slice
b := []int{} // empty, non-nil
c := make([]int, 0) // empty, non-nil
fmt.Println("a len", len(a), "nil", a == nil)
fmt.Println("b len", len(b), "nil", b == nil)
fmt.Println("c len", len(c), "nil", c == nil)
fmt.Println("all empty?", len(a) == 0 && len(b) == 0 && len(c) == 0)
}You should see length 0 for all three, nil true only for a, and all empty? true.
Maps and channels
var m map[string]int starts as a nil map: reading is safe, but writing panics until you assign a map from make or a literal. m == nil distinguishes “not allocated” from an empty but allocated map (len(m) == 0 can be true for both). Channels behave similarly: var ch chan int is nil; ch == nil is the idiomatic check before a non-blocking receive or close.
golang check if struct is empty (structs are never nil)
You cannot write var v MyStruct; v == nil—a struct value is never nil. For check if struct is empty golang (same intent as golang check if struct is empty) you usually mean “all fields are zero”: compare important fields, or use reflect.ValueOf(v).IsZero() for a generic test (handles nested structs for exported fields as documented in reflect).
To represent “no value,” use a pointer: var cfg *Config; cfg == nil is valid and common for optional configuration.
golang check if interface is nil (typed nil trap)
An interface value holds a dynamic type and a dynamic value. var v any is a true nil interface: v == nil is true. If you assign a typed nil pointer into that interface, the dynamic type is no longer “absent,” so v == nil becomes false even though the pointer inside is nil:
package main
import "fmt"
func main() {
var i any
fmt.Println("zero interface:", i == nil)
var p *int
i = p
fmt.Println("interface holding typed nil *int:", i == nil)
}zero interface: true
interface holding typed nil *int: falseThat behavior is a frequent source of bugs for people learning golang check if interface is nil. Practical fixes: keep a concrete *T and test p == nil before converting to any, or document that callers must check the concrete type. The Go FAQ entry on nil errors discusses the same underlying idea for error values.
Summary
Golang nil applies to pointers, slices, maps, channels, functions, and interfaces—not to struct, string, or numeric values. For a golang nil pointer or golang null pointer style check, use p == nil. For check if slice is empty golang, prefer len(s) == 0; use s == nil when the distinction between nil and empty slices matters. Structs are never nil; golang check if struct is empty means zero fields or a *Struct that may be nil. For interfaces, == nil is only true when both type and value are unset—assigning a typed nil into an any or error breaks the naive check, so test the concrete value or design APIs to avoid hiding typed nils behind interfaces.
References
- The zero value (Go spec)
- Comparison operators (Go spec)
- Errors and nil (Go FAQ)
- Handle errors (tutorial)
reflect.Value.IsZero- Zero time and
IsZero

