Free — no signup required

Resource Cleanup: The Defer Keyword

2 min read

Don't Forget to Close the Door

Think of defer like a "cleanup note" you write at the top of a function. No matter how the function exits — normal return, early return due to an error, or even a panic — Go executes all deferred statements before the function returns, in last-in-first-out order.

This solves a real problem. Without defer, you have to remember to close files, release locks, and disconnect from databases at every possible exit point in a function. Miss one, and you have a resource leak.

package main

import (
    "fmt"
    "os"
)

func processConfig(filename string) error {
    f, err := os.Open(filename)
    if err != nil {
        return fmt.Errorf("open config: %w", err)
    }
    defer f.Close() // Guaranteed to run when processConfig returns

    // Parse the file...
    // If parsing fails and we return early, f.Close() still runs.
    // If parsing succeeds and we return nil, f.Close() still runs.

    fmt.Println("Config processed successfully")
    return nil
}

Multiple defers execute in reverse order (LIFO)

func example() {
    defer fmt.Println("third")  // runs last
    defer fmt.Println("second") // runs second
    defer fmt.Println("first")  // runs first
    fmt.Println("function body")
}
// Output:
// function body
// first
// second
// third

This LIFO ordering is intentional — it mirrors the natural "undo" order of setup operations. If you open a database connection and then start a transaction, you want to roll back the transaction before closing the connection.

defer with cancel() — the most common Ops pattern

Every time you create a context.WithTimeout or context.WithCancel, you must call the returned cancel function to release the timer and associated resources. The idiomatic pattern is:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() // Always on the very next line

If you forget defer cancel(), the context's internal timer goroutine leaks until the parent context is cancelled. In a long-running service that creates many contexts, this accumulates into a goroutine leak — a subtle but serious production issue.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free