Nil slice — zero value of []T; pointer is nil, length and capacity are 0. Empty slice — has a backing array but no elements; length is 0 but capacity may be > 0.
Both support len, cap, range, and append identically. The practical difference appears in JSON marshaling and equality checks.
1var nilS []int // nil slice2emptyS := []int{} // non-nil, empty3madeS := make([]int, 0, 5) // non-nil, empty, cap=545// append works on all three6nilS = append(nilS, 1) // [1]7emptyS = append(emptyS, 2) // [2]8madeS = append(madeS, 3) // [3]910fmt.Println(nilS == nil) // true11fmt.Println(emptyS == nil) // false12fmt.Println(madeS == nil) // false
JSON serialization:
1n, _ := json.Marshal(nilS) // "null"2e, _ := json.Marshal(emptyS) // "[]"
When to use:
[] instead of null in JSON.Common mistakes:
[].len == 0 when nil vs empty matters.append(nilSlice, ...) panics — it doesn't.slices.Equal(nilS, emptyS) — they are not equal despite same length.