Understanding Defer in Go
Learn how defer works in Go and why it's a useful feature for writing clean and maintainable code.
What is Defer in Go
According to “A Tour of Go”,
A defer statement defers the execution of a function until the surrounding function returns.
It’s basically like saying,
“Once everything else is done, I’ll make sure to run this bit of code”.
Defer ensures that certain actions that need to happen actually happen. Typical use cases are closing a file stream or database connection once we are done with it.
Reference: go.dev/tour/flowcontrol/12
From a More Practical Sense
Think about cooking - after preparing the meal, you know you need to clean your utensils. Not doing so might leave you with a pile of dirty dishes and a bad experience later.
Similarly, defer ensures that necessary cleanup happens automatically, so you don’t end up with a messy state in your program.
Implementing Defer
Specifying Defer Inline
1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("Program started")
7
8 defer fmt.Println("Deferred message: mimics calling a deferred implementation")
9
10 fmt.Println("Program ended")
11}
Output
1Program started
2Program ended
3Deferred message: mimics calling a deferred implementation
Deferring a Function
1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("Program started")
7
8 defer deferredFunction()
9
10 fmt.Println("Program ended")
11}
12
13func deferredFunction() {
14 fmt.Println("Implemented in deferredFunction")
15 fmt.Println("This function will be executed at the end of the main function")
16}
Output
1Program started
2Program ended
3Implemented in deferredFunction
4This function will be executed at the end of the main function
Deferring a Function with Return Values
Incorrect
1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("Program started")
7
8 defer hello = deferredFunction() // compilation error
9
10 fmt.Println("Program ended")
11}
12
13func deferredFunction() string {
14 fmt.Println("Implemented in deferredFunction")
15 fmt.Println("This function will be executed at the end of the main function")
16 return "Deferred function executed"
17}
Correct
1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("Program started")
7
8 defer fmt.Println(deferredFunction())
9
10 fmt.Println("Program ended")
11}
12
13func deferredFunction() string {
14 fmt.Println("Implemented in deferredFunction")
15 fmt.Println("This function will be executed at the end of the main function")
16 return "Deferred function executed"
17}
Output
1Program started
2Implemented in deferredFunction
3This function will be executed at the end of the main function
4Program ended
5Deferred function executed
Dealing with Multiple Defers
When multiple defer statements are used within a function, they are executed in reverse order (Last In, First Out - LIFO).
This creates a predictable and controlled cleanup process.
Imagine you have guests over for dinner, and when it’s time to clean up, you probably wouldn’t wash one dish, then sweep part of the sitting area, then mop the table, and then wash another dish. Instead, you’d likely want to tackle the tasks in a preferred order—finishing up by mopping the table first, then doing the dishes, and finally sweeping the floor.
This way, everything gets done in a logical and efficient sequence, just like how deferred functions are executed in Go as LIFO.
1package main
2
3import "fmt"
4
5func cookDinner() {
6 fmt.Println("Cooking dinner...")
7}
8
9func setTable() {
10 fmt.Println("Setting the table...")
11}
12
13func cleanDishes() {
14 fmt.Println("Cleaning the dishes...")
15}
16
17func turnOffLights() {
18 fmt.Println("Turning off the lights...")
19}
20
21func dinner() {
22
23 defer turnOffLights()
24 defer cleanDishes()
25
26 cookDinner()
27 setTable()
28
29 fmt.Println("Dinner is ready, enjoy!")
30 fmt.Println("Done with Dinner! Start cleaning up...")
31}
32
33func main() {
34 dinner()
35}
Output
1Cooking dinner...
2Setting the table...
3Dinner is ready, enjoy!
4Done with Dinner! Start cleaning up...
5Cleaning the dishes...
6Turning off the lights...
In this example, as far as the defer statements are concerned cleanDishes() is specified last but executed first where as turnOffLights() is specified first but executed last. This is due to the Last In, First Out (LIFO) nature when dealing with multiple defers.
A Small Catch
“The deferred call’s arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.”
Reference: go.dev/tour/flowcontrol/12
Understanding Evaluation of Arguments
1package main
2
3import "fmt"
4
5func deferredFunction(x, y int) {
6 fmt.Println("Deferred function called with x:", x, "and y:", y)
7}
8
9func main() {
10
11 a := 10
12 b := 20
13
14 defer deferredFunction(a, b)
15
16 a = 30
17 b = 40
18
19 fmt.Println("Values inside of main a:", a, "b:", b)
20}
Output
1Values inside of main a: 30 b: 40
2Deferred function called with x: 10 and y: 20
In this example, deferredFunction() is called when a is 10 and b is 20. However, since deferredFunction() is called with a ‘defer’ execution of this function is delayed and not executed immediately. Later down the flow, a is modified to 30 and b to 40, but this doesn’t matter, because when deferredFunction() executes eventually (when its ready to execute) it will use the same arguments that were originally passed onto it (10 & 20)
Summary
- defer in Go is a keyword used to schedule a function call to be executed after the surrounding function returns.
- When multiple defer functions are called it will be executed in reversed order (LIFO - Last In, First Out).
- Although the function is delayed, the arguments that are evaluated would be the original arguments that were passed at the time defer was encountered.
- Use cases: Commonly used for ensuring cleanup tasks, like closing files, releasing DB connections etc.
About the Author

Sashitha Fonseka
In my blog, I break down topics that interest me into simple, digestible bits, the way I would explain them to myself when I was first trying to figure things out.
A big part of how I learn is by framing technical concepts as narratives to make them easier to understand and remember.
My goal in writing these blogs is to deepen my own understanding and hopefully help others learn along the way and apply these concepts to solve real-world problems. Feedback is always welcome, so feel free to reach out.