SWIFT

Swift Lazy Var: Syntax, Behavior, and Practical Use Cases

A Swift lazy var is a property that delays its initialization until the first time it's accessed. This feature is useful for improving performance and managing complex dependencies. With lazy var Swift allows developers to declare properties that are expensive to compute, require external data, or depend on runtime context—without initializing them during object creation.

Using lazy properties helps optimize memory usage and avoids unnecessary setup when certain values aren’t needed immediately. In large applications or complex objects, Swift lazy var declarations can help you write cleaner and more efficient code.


What Is a Lazy Var in Swift?

A lazy var in Swift is a stored property that is initialized only once, the first time it's accessed. It must always be declared as a variable (var)—not a constant (let)—because its value is not set until later.

Here's a basic example:

class DataManager {
    lazy var data: [String] = {
        print("Loading data...")
        return ["User1", "User2", "User3"]
    }()
}

When the data property is accessed for the first time, the closure is executed and the result is stored. All future accesses use the stored value without re-running the initialization.


Syntax of Swift Lazy Var

To declare a lazy variable, you simply use the lazy keyword before var and assign it a value—often through a closure:

lazy var propertyName: Type = {
    // initialization logic
    return someValue
}()

Example:

lazy var filePath: String = {
    let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    return documents.appendingPathComponent("notes.txt").path
}()

This lazy var Swift setup ensures that filePath isn't calculated until it’s actually needed.


When Should You Use Lazy Var in Swift?

Using Swift lazy var is ideal in scenarios where:

  • Initialization is expensive or time-consuming (e.g., loading data from disk or network)
  • The property depends on self (which is not available during default property initialization)
  • You don’t need the property value unless a specific condition occurs
  • You want to defer memory usage for a heavy resource until absolutely necessary

This approach helps reduce unnecessary memory allocation and improve app responsiveness.


How Lazy Var Works in Memory

When a Swift lazy var is declared, it doesn’t occupy memory or compute its value during the object’s initialization phase. Instead, Swift creates a placeholder reference. The actual initialization happens the moment the property is read for the first time.

This behavior is thread-safe as of Swift 4.0 and newer. Swift uses a lock behind the scenes to ensure the initialization code is not executed more than once, even in multi-threaded environments.


Lazy Var vs Computed Property

It’s easy to confuse lazy properties with computed properties. Here's the distinction:

  • A lazy var stores a value. It’s computed once, then retained.
  • A computed property is recalculated every time it’s accessed and doesn’t store a value.

Example of a computed property:

var fullName: String {
    return "\(firstName) \(lastName)"
}

Example of a lazy stored property:

lazy var config: Config = {
    return Config.load()
}()

The Swift lazy var allows you to execute setup code once and reuse the result.


Accessing Self in a Lazy Var

One major benefit of using a lazy variable in Swift is that you can reference self inside the initialization closure. This is not possible in normal stored property initializers because self isn’t fully available until all properties are initialized.

For example:

class Profile {
    let name: String

    lazy var greeting: String = {
        return "Hello, \(self.name)"
    }()

    init(name: String) {
        self.name = name
    }
}

Here, greeting depends on self.name, and using a lazy var makes it possible to defer access until self is ready.


Using Lazy Vars in Structs

Lazy properties can only be declared on classes—not on structs—because structs are value types and copied by value. Swift doesn’t allow lazy var in structs due to the complexities of managing deferred state across copies.

Attempting this will cause a compile-time error:

struct Person {
    lazy var address = "Unknown" // ❌ Error
}

If you need laziness in structs, consider using computed properties or refactoring your logic.


Combining Lazy Var with Closures and Configuration

Swift lazy var can be used effectively with closures to configure complex objects:

lazy var tableView: UITableView = {
    let table = UITableView()
    table.rowHeight = 44
    table.separatorStyle = .singleLine
    return table
}()

This technique avoids repetitive code and keeps your view configuration contained within a single block.


Using Lazy Var with Dependency Injection

Lazy properties are also helpful when using dependency injection. You can delay injecting a dependency until it’s really needed:

class AnalyticsService {
    func logEvent(_ event: String) { print("Logged \(event)") }
}

class AppController {
    lazy var analytics: AnalyticsService = {
        return AnalyticsService()
    }()
}

In this example, analytics will only be created if an event needs to be logged, avoiding unnecessary instantiation at startup.


Best Practices for Lazy Var in Swift

To use lazy var Swift efficiently, follow these guidelines:

  • Don’t overuse lazy vars just to save a few lines—they’re most useful for expensive or optional properties.
  • Keep the initialization logic short and focused.
  • Use them when accessing self is necessary inside a stored property.
  • Avoid laziness for properties that are always accessed immediately after object creation.
  • Use lazy properties to defer third-party framework setup (e.g., UI components, network clients, etc.).

Common Pitfalls with Lazy Vars

While Swift lazy var is powerful, here are common mistakes:

  • Forgetting that lazy vars must be var, not let
  • Misusing them for simple values that could be constants
  • Declaring lazy vars in structs
  • Assuming they’re thread-safe in older Swift versions (before Swift 4.0)
  • Using long or complex initialization closures that harm readability

Being aware of these limitations helps you avoid subtle bugs or design issues.

Learn to Code in Swift for Free
Start learning now
button icon
To advance beyond this tutorial and learn Swift by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH

Reach your coding goals faster