# Defer in Swift explained with Code Examples

> Source: <https://www.avanderlee.com/swift/defer-usage-swift/>
> Published: 2026-07-06 12:51:59+00:00

Although the defer keyword was already introduced in Swift 2.0, it’s still quite uncommon to use it in projects. Its usage can be hard to understand, but using it can improve your code a lot in some places.

The most common use case seen around is opening and closing a context within a scope. Starting in Swift 6.4, `defer`

can also await asynchronous cleanup when used inside an `async`

context, making it even more useful for modern Swift Concurrency code.

[Share your AI agent’s work with your team](https://display.dev/?utm_source=swiftlee&utm_medium=newsletter&utm_campaign=swiftlee_sponsor)Your agent generates a report, dashboard, or prototype as HTML or Markdown. display.dev turns it into a secure URL your team can open with their existing work login, comment on inline, and send back to any agent through MCP. Works with Cursor, Codex, Claude Code, and more. No viewer accounts, no seat management, no vendor lock-in.

[Learn more](https://display.dev/?utm_source=swiftlee&utm_medium=newsletter&utm_campaign=swiftlee_sponsor).

How does it work?

A defer statement is used for executing code just before transferring program control outside of the scope that the statement appears in.

```
func updateImage() {
    defer { print("Did update image") }

    print("Will update image")
    imageView.image = updatedImage
}

// Prints:
// Will update Image
// Did update image
```

Order of execution with multiple defer statements

If multiple statements appear in the same scope, the order they appear is the reverse of the order they are executed. The last defined statement is the first to be executed which is demonstrated by the following example by printing numbers in logical order.

```
func printStringNumbers() {
    defer { print("1") }
    defer { print("2") }
    defer { print("3") }

    print("4")
}

/// Prints 4, 3, 2, 1
```

The same reverse order applies when a `defer`

body contains asynchronous work in Swift 6.4: each deferred block runs on scope exit, and asynchronous work is awaited before continuing (more about this later).

FREE 5-Day Email Course: The Swift Concurrency Playbook

A **FREE 5-day email course** revealing the **5 biggest mistakes** iOS developers make with with async/await that lead to App Store rejections And migration projects taking months instead of days (even if you've been writing Swift for years)

A common use case

The most common use case seen around is opening and closing a context within a scope, for example when handling access to files. A `FileHandle`

requires to be closed once the access has been finished. You can benefit from the defer statement to ensure you don’t forget to do this.

``` js
func writeFile() {
    let file: FileHandle? = FileHandle(forReadingAtPath: filepath)
    defer { file?.closeFile() }

    // Write changes to the file
}
```

Awaiting asynchronous cleanup with defer

Swift 6.4 implements [SE-0493: Support async calls in defer bodies](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0493-defer-async.md), allowing you to use `await`

inside a `defer`

block when the surrounding context is already asynchronous.

Before Swift 6.4, cleanup that required `await`

had to be repeated across multiple exit paths or moved into a separate unstructured task. You can now keep setup and teardown close together:

``` js
func importArticles() async throws {
    let importer = ArticleImporter()
    await importer.open()

    defer {
        await importer.close() // Allowed from Swift 6.4
    }

    try await importer.importLatestArticles()
}
```

The `defer`

body still runs when leaving scope, just like synchronous `defer`

statements. The difference is that Swift now implicitly awaits the asynchronous cleanup before the function returns.

*If you are new to this syntax, start with my article on async/await in Swift or read more about structured concurrency.*

Why not create a Task?

You might wonder why you can’t simply use a `Task`

like you did before Swift 6.4:

``` js
func importArticles() async throws {
    let importer = ArticleImporter()
    await importer.open()

    defer {
        Task {
            await importer.close()
        }
    }

    try await importer.importLatestArticles()
}
```

While this compiles, it starts unstructured work and allows `importArticles()`

to return before cleanup finishes. In other words, you lose the guarantee that made `defer`

useful in the first place.

Ensuring results

A more advanced usage of the statement is by ensuring a result value to be returned in a completion callback. This can be very handy as it’s easy to forget to trigger this callback.

``` php
func getData(completion: (_ result: Result<String>) -> Void) {
    var result: Result<String>?

    defer {
        guard let result = result else {
            fatalError("We should always end with a result")
        }
        completion(result)
    }

    // Generate the result..
}
```

The statement makes sure to execute the completion handler at all times and verifies the result value. Whenever the result value is `nil`

, the fatalError is thrown and the application fails.

A few rules to remember

When using defer in Swift, it’s good to remember the following rules:

- You can only use
`await`

in`defer`

when the surrounding context supports concurrency - Deferred blocks still execute in reverse order
- Asynchronous cleanup is awaited before leaving scope
- Cancellation is not suppressed: code inside
`defer`

can still observe`Task.isCancelled`

In other words, if you’re using `async`

inside a `defer`

block while the outer method isn’t marked as asynchronous, you’ll run into the following error:

Frequently Asked Questions around defer

I first published this article in 2018, and I have collected quite a few questions since. Here are a few common ones, mostly related to the latest Swift Concurrency changes:

**Can you use await inside defer in Swift?** Yes, starting in Swift 6.4, you can use `await`

inside `defer`

when the surrounding context is asynchronous.

**Does async defer require a new syntax?** No. You still write `defer { await cleanup() }`

, not `defer async { ... }`

.

**Does async defer ignore cancellation?** No. Code inside `defer`

can still observe task cancellation.

[Share your AI agent’s work with your team](https://display.dev/?utm_source=swiftlee&utm_medium=newsletter&utm_campaign=swiftlee_sponsor)Your agent generates a report, dashboard, or prototype as HTML or Markdown. display.dev turns it into a secure URL your team can open with their existing work login, comment on inline, and send back to any agent through MCP. Works with Cursor, Codex, Claude Code, and more. No viewer accounts, no seat management, no vendor lock-in.

[Learn more](https://display.dev/?utm_source=swiftlee&utm_medium=newsletter&utm_campaign=swiftlee_sponsor).

**Conclusion**

I love using defer in my code, but I also find it a feature that’s not commonly used. The fact is, you can write your code without using it. However, I truly believe your code will become cleaner in many places when you take advantage of using `defer`

.

If you want to improve your Swift knowledge even more, check out the [Swift category page](https://www.avanderlee.com/swift/). Feel free to contact me or [tweet me on Twitter](https://twitter.com/twannl) if you have any additional tips or feedback.

Thanks!
