defer is used to ensure that a function call is performed later in a program’s execution, usually for purposes of cleanup. defer is often used where ensure and finally would be used in other languages.
A deferred function call is executed when the surrounding function returns, regardless of how it returns:
func main() { // Immediately after getting a file object with // createFile, we defer the closing of that file // with closeFile. This will be executed at the end // of the enclosing function (main), after // writeFile has finished. path := filepath.Join(os.TempDir(), "defer.txt") f := createFile(path) defer closeFile(f) writeFile(f)}
Deferred functions are executed in LIFO (Last In, First Out) order when the surrounding function returns.
rows, err := db.Query("SELECT * FROM users")if err != nil { return err}defer rows.Close()// Process rows// Connection will be closed when function returns
package mainimport ( "fmt" "os" "path/filepath")// Suppose we wanted to create a file, write to it,// and then close when we're done. Here's how we could// do that with defer.func main() { path := filepath.Join(os.TempDir(), "defer.txt") f := createFile(path) defer closeFile(f) writeFile(f)}func createFile(p string) *os.File { fmt.Println("creating") f, err := os.Create(p) if err != nil { panic(err) } return f}func writeFile(f *os.File) { fmt.Println("writing") fmt.Fprintln(f, "data")}func closeFile(f *os.File) { fmt.Println("closing") err := f.Close() if err != nil { panic(err) }}
You can have multiple defer statements in a single function. They execute in reverse order (LIFO):
func main() { defer fmt.Println("First") defer fmt.Println("Second") defer fmt.Println("Third") fmt.Println("Main function")}// Output:// Main function// Third// Second// First
Deferred functions are executed in Last In, First Out (LIFO) order, which makes sense for cleanup operations that need to happen in reverse order of acquisition.
While defer has minimal overhead, in extremely performance-critical code, direct cleanup calls might be slightly faster. However, the readability and safety benefits usually outweigh this.
Be careful when using defer inside loops. Deferred functions accumulate and only execute when the surrounding function returns, not at the end of each iteration.
// Bad: Resource leak in loopfor _, file := range files { f, _ := os.Open(file) defer f.Close() // Won't close until function ends // Process file}// Good: Use a separate functionfor _, file := range files { processFile(file)}func processFile(filename string) error { f, err := os.Open(filename) if err != nil { return err } defer f.Close() // Closes after each iteration // Process file return nil}