Should You Return Empty or Nil Slices in Go?
In Go, we often need to return zero values. Idiomatic Go encourages the use of guard clauses, and guard clauses necessitate the need to return early. When returning early with an error, by convention all other return values should be zero values. The confusion arises with data types like maps and slices. Should maps and slices be returned as a simple nil value, or should an empty but instantiated value be returned?
For example, should we use this syntax?
func getItems(url string) ([]string, error) {
data, err := makeRequest(url)
if err != nil {
return nil, err
}
items, err := unpack(data)
if err != nil {
return nil, err
}
return data, nil
}
Or perhaps this syntax?
func getItems(url string) ([]string, error) {
data, err := makeRequest(url)
if err != nil {
return []string{}, err
}
items, err := unpack(data)
if err != nil {
return []string{}, err
}
return data, nil
}
The Differences
I ran a quick bit of code to show some of the differences between nil and empty slices:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var nilSlice []string
fmt.Println(nilSlice) // Output: []
fmt.Println(len(nilSlice), cap(nilSlice)) // Output: 0 0
fmt.Println(nilSlice == nil) // Output: true
dat, _ := json.Marshal(nilSlice)
fmt.Println(string(dat)) // Output: null
emptySlice := []string{}
fmt.Println(emptySlice) // Output: []
fmt.Println(len(emptySlice), cap(emptySlice)) // Output: 0 0
fmt.Println(emptySlice == nil) // Output: false
dat, _ = json.Marshal(emptySlice)
fmt.Println(string(dat)) // Output: []
}
As you can see there are some similarities between nil and empty slices:
- Both have zero length and cap
- Both print
[] - Both can be used the same way in range loops and append functions (not shown here)
They differ in the following ways:
- Only a
nilslice will succeed a nil check - When encoded as JSON using the standard library, the nil slice becomes
nulland the empty slice becomes[]
Which Should I Do?
Generally speaking, prefer nil.
According to the Go wiki, nil is the preferred style. When we just need to return an empty slice nil will work great in practically all cases. It’s also easier to type nil than []string{} or make([]string, 0) and typically gets syntax highlighted which makes it easier to read.
Related Articles
Top 15 Golang Interview Questions [Updated 2026]
Aug 31, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
Let’s take a look at some good technical questions to be familiar with, whether you are looking to nail your next Golang interview, or if you’re the interviewer yourself..
Unexpected Printf Behavior in Go WASM - Nothing Prints
Aug 10, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
While working on boot.dev’s Go Playground, I came across a very strange error. The standard library’s fmt.Printf() function prints nothing to the console when called. Nothing.
Authenticate Users with "Sign In With Google" in Golang
Jul 22, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
Users love convenience. If your goal is to make it easy for users to register with your app or website, then implementing the “Sign in with Google” option should be at the top of your priority list. If you are like me, then you may find Google’s documentation on the subject to be lackluster at best, and downright confusing at worst. Here we will go step-by-step through the authentication process so you can implement Google sign-in easily.
Rust Backend vs Go Backend in Web Development
Jul 17, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
Rust and Go are two of the industry’s biggest successes when it comes to developing modern programming languages. Both languages compete in terms of backend web development, and it’s a fierce competition. Golang and Rust are new languages, have growing communities, and are fast and efficient. When it comes to microservice architectures, frameworks, and apps, Rust and Go are household names on the backend.