ZetCode

Golang defer keyword

last modified May 7, 2025

This tutorial explains how to use the defer keyword in Go. We'll cover defer basics with practical examples of resource cleanup and execution control.

The defer statement postpones the execution of a function until the surrounding function returns. It's commonly used for cleanup operations like closing files or unlocking mutexes.

In Go, defer ensures important cleanup code runs even if the function exits early. Deferred calls execute in last-in-first-out order when the function completes.

Basic defer example

The simplest use of defer postpones a function call until after the surrounding function completes. This example shows basic defer behavior.

basic_defer.go
package main

import "fmt"

func main() {
    defer fmt.Println("This prints last")
    fmt.Println("This prints first")
    fmt.Println("This prints second")
}

The deferred call executes after all non-deferred statements in the function. Deferred calls are pushed onto a stack and executed in reverse order.

Defer with file operations

defer is commonly used to ensure resources are properly closed. This example demonstrates file cleanup with defer.

file_defer.go
package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.Create("test.txt")
    if err != nil {
        panic(err)
    }
    
    defer file.Close()
    
    fmt.Fprintln(file, "Writing to file")
    fmt.Println("File operations complete")
}

The file.Close() call is deferred until main() exits. This ensures the file is properly closed even if an error occurs during file operations.

Multiple defer statements

When multiple defer statements exist, they execute in reverse order. This example demonstrates the LIFO (last-in-first-out) behavior of defer.

multi_defer.go
package main

import "fmt"

func main() {
    defer fmt.Println("First defer - runs last")
    defer fmt.Println("Second defer - runs second")
    defer fmt.Println("Third defer - runs first")
    
    fmt.Println("Main function executing")
}

Deferred calls are pushed onto a stack. The last defer registered is the first one executed when the function exits. This behavior is crucial for proper resource cleanup.

Defer with function arguments

Arguments to deferred functions are evaluated immediately, not when the function executes. This example shows argument evaluation timing.

defer_args.go
package main

import "fmt"

func main() {
    i := 0
    defer fmt.Println("Deferred print:", i)
    i++
    fmt.Println("Regular print:", i)
}

The deferred fmt.Println captures the value of i (0) when the defer statement is executed, not when the function exits. The regular print shows the updated value (1).

Defer in loops

Using defer inside loops requires caution as deferred calls don't execute until the function exits. This example demonstrates loop defer behavior.

loop_defer.go
package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        defer fmt.Println("Deferred in loop:", i)
        fmt.Println("In loop:", i)
    }
    
    fmt.Println("Loop completed")
}

All deferred calls in the loop accumulate and execute in reverse order after the loop completes. Each iteration's defer captures the current value of i.

Defer with named return values

Deferred functions can modify named return values. This example shows how defer affects function return values.

defer_return.go
package main

import "fmt"

func main() {
    fmt.Println("Result:", calculate())
}

func calculate() (result int) {
    defer func() {
        result *= 2
    }()
    
    result = 10
    return
}

The deferred function executes after the return statement but before the function actually returns. It doubles the named return value result.

Practical example: Database cleanup

This practical example demonstrates using defer for database connection cleanup in a real-world scenario.

db_defer.go
package main

import (
    "database/sql"
    "fmt"
    "log"
    
    _ "github.com/lib/pq"
)

func main() {
    db, err := sql.Open("postgres", "user=test dbname=test sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    rows, err := db.Query("SELECT id, name FROM users")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    
    for rows.Next() {
        var id int
        var name string
        if err := rows.Scan(&id, &name); err != nil {
            log.Fatal(err)
        }
        fmt.Printf("ID: %d, Name: %s\n", id, name)
    }
    
    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }
}

The example shows proper resource cleanup with defer for both the database connection and query results. This pattern ensures resources are released even if errors occur during processing.

Source

Go language specification

This tutorial covered the defer keyword in Go with practical examples of resource management and execution control.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Golang tutorials.