Nil slice — declared without initialization; pointer, length, and capacity are all zero. Empty slice — initialized but contains no elements; may have capacity > 0.
Both behave identically for len, cap, range, and append. The difference shows up in JSON serialization and equality checks.
1var nilS []int2emptyS := []int{}3madeS := make([]int, 0, 10)45// All support append6nilS = append(nilS, 1) // [1]7emptyS = append(emptyS, 2) // [2]8madeS = append(madeS, 3) // [3]
JSON marshaling:
1n, _ := json.Marshal(nilS) // "null"2e, _ := json.Marshal(emptyS) // "[]"
When to use:
[] not null.Common mistakes:
null instead of [].len == 0 when nil vs empty matters.append(nilSlice, ...) is safe — no panic.slices.Equal(nilS, emptyS) returns false despite both being empty.