defer schedules a function call to run when the surrounding function returns. It keeps cleanup beside successful resource acquisition.
Close resources reliably
file, err := os.Open(name)
if err != nil {
return err
}
defer file.Close()
Register the cleanup only after acquisition succeeds. For resources whose close error matters, handle it explicitly rather than discarding it.
Defers run last-in, first-out
defer fmt.Println("first")
defer fmt.Println("second")
This prints second, then first. Stack ordering is useful when later setup depends on earlier resources.
Arguments are evaluated immediately
name := "before"
defer fmt.Println(name)
name = "after"
The deferred call prints before. To read the later value, defer a closure that captures the variable.
Keep loop lifetimes small
Defers run at function return, not the end of a loop iteration. A loop that opens thousands of files and defers every close retains them all. Extract one iteration into a helper function so cleanup happens promptly.
Defer and panic
Deferred calls still execute while a panic unwinds the stack. This makes them appropriate for releasing locks and resources. Recovery should normally happen only at a clear process boundary such as an HTTP middleware, where the failure can be logged and converted to a stable response.
Defer has a small cost, but clarity is usually more valuable. Optimize it away only after measurement proves cleanup scheduling matters in a genuinely hot path.