Skip to main content
The defer statement in Go schedules a function call to be executed immediately before the surrounding function returns. It pushes the deferred function call onto an internal stack, guaranteeing execution whether the surrounding function terminates normally (via a return statement) or abruptly (via a panic). However, deferred functions are not executed if the program terminates directly via os.Exit() or functions that call it internally (such as log.Fatal()).
The behavior of defer is governed by three strict mechanical rules regarding evaluation, execution order, and return value interaction.

1. Immediate Argument Evaluation

The arguments passed to a deferred function are evaluated at the exact moment the defer statement is encountered during execution, not when the deferred function is eventually invoked.
Note: If the deferred function is a method, the receiver is also evaluated immediately.

2. LIFO Execution Order

When multiple defer statements are declared within the same function, they are pushed onto a call stack. Upon the surrounding function’s return, these deferred calls are popped off the stack and executed in Last-In, First-Out (LIFO) order.

3. Interaction with Named Return Values

Deferred functions are executed after the surrounding function’s return statement updates the return variables, but before the function actually yields control back to its caller. Consequently, a deferred anonymous function can read and modify the surrounding function’s named return values.

Scope and Memory Considerations

A critical technical distinction in Go is that defer is bound to function scope, not block scope. If a defer statement is placed inside a nested lexical block (such as a for loop), the deferred function will not execute when the block terminates. It will only execute when the parent function returns.
Because the defer stack allocates memory for each deferred call and its evaluated arguments, placing defer inside unbounded or large loops can lead to excessive memory consumption or stack overflows. To force block-level defer execution, the block must be wrapped in an anonymous function (or closure) that is invoked immediately.
Tired of Poor Go Skills? Fix That With Deep Grasping!Learn More