TechnologiesSwiftUI

AppStorage struct

iOSmacOStvOSwatchOSvisionOSiOS 14.0+✓ renders

A property wrapper type that reflects a value from `UserDefaults` and

How it works

AppStorage is a property wrapper that reads and writes a value in the user's defaults store, exposing it to your views as a source of truth. Reading the property returns the persisted value, and writing it both saves to user defaults and invalidates any views that depend on it, so the interface stays in sync with what's on disk. Reach for AppStorage when you want a small piece of state — a preference, a flag, the last value a person entered — to survive across launches without writing your own persistence layer. It behaves like State, but the value lives in UserDefaults rather than in memory.

  1. Declare a wrapped property with a key and default

    Annotate a stored property with @AppStorage and pass the user-defaults key as its argument; the property's initial value becomes the fallback used when no value has been saved yet. Here @AppStorage("username") private var username: String = "Guest" reads the "username" key, defaulting to "Guest", and @AppStorage("isDarkMode") private var isDarkMode: Bool = false does the same for a Bool.

  2. Use the supported value types

    AppStorage works with the property-list types UserDefaults understands — String, Bool, Int, Double, Data, URL, and RawRepresentable types whose raw value is one of those. The example stores a String in username and a Bool in isDarkMode, each a natively supported type that needs no extra conversion.

  3. Read the wrapped value directly

    Accessing the property by name yields the current persisted value, and the enclosing view re-renders whenever that stored value changes. Text("Hello, \(username)!") reads username straight out of the wrapper, so the greeting reflects whatever was last saved to defaults.

  4. Bind to the projected value with $

    The $ prefix projects a Binding to the stored value, which controls write back into user defaults whenever a control mutates it. TextField("Username", text: $username) and Toggle("Dark Mode", isOn: $isDarkMode) both write through these bindings, so each keystroke or toggle persists immediately.

  5. Scope storage with a custom store

    By default AppStorage uses UserDefaults.standard, but an initializer overload accepts a store: parameter so you can target a shared suite — for example a defaults instance backed by an app group. The example relies on the standard store, which is the right choice for per-app preferences like username and isDarkMode.

Try it — Type a new name into the TextField bound to $username, then relaunch the app — the greeting reappears with your name instead of "Guest", because AppStorage restored it from user defaults.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

AppStorage.swift
struct AppStorageDemo: View {
    @AppStorage("username") private var username: String = "Guest"
    @AppStorage("isDarkMode") private var isDarkMode: Bool = false

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Hello, \(username)!")
                .font(.headline)
            TextField("Username", text: $username)
                .textFieldStyle(.roundedBorder)
            Toggle("Dark Mode", isOn: $isDarkMode)
        }
        .padding()
    }
}
Live preview
Hello, Guest! Guest Dark Mode
Hello, Guest! Guest Dark Mode
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →