Swift
UserDefaults
iOS Development
Swift Programming
App Storage

How can I use UserDefaults in Swift?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

UserDefaults is the standard key-value store for lightweight persistent settings in a Swift app. It is a good fit for preferences and small flags, but it is the wrong tool for secrets, large blobs, or data that needs rich querying.

What UserDefaults Is Good For

UserDefaults is a key-value store backed by the app's defaults database. It works well for values such as:

  • dark mode preference
  • last selected tab
  • onboarding-complete flag
  • preferred measurement units

It supports property-list friendly types such as String, Int, Double, Bool, Data, arrays, dictionaries, and URL.

If the data is complex, private, or large, another storage option is usually better.

Save and Read Simple Values

The basic API is intentionally direct. Write with set, then read back with the matching typed getter.

swift
1import Foundation
2
3let defaults = UserDefaults.standard
4
5defaults.set(true, forKey: "hasSeenOnboarding")
6defaults.set("metric", forKey: "units")
7
8let seen = defaults.bool(forKey: "hasSeenOnboarding")
9let units = defaults.string(forKey: "units") ?? "imperial"
10
11print(seen)
12print(units)

When you know the type, use the typed getters such as bool(forKey:), integer(forKey:), or string(forKey:). That keeps the code clearer than using object(forKey:) everywhere.

Remove a Stored Value

If you no longer want a preference stored, remove it explicitly.

swift
let defaults = UserDefaults.standard
defaults.removeObject(forKey: "units")

After removal, reading the value again returns the default behavior for that getter, such as false for a missing boolean or nil for a missing string.

Use a Centralized Key Definition

Hard-coded string keys scattered across the codebase eventually cause typos and inconsistent naming. A small key namespace keeps things safer.

swift
1enum DefaultsKey {
2    static let hasSeenOnboarding = "hasSeenOnboarding"
3    static let units = "units"
4}
5
6let defaults = UserDefaults.standard
7defaults.set(true, forKey: DefaultsKey.hasSeenOnboarding)
8let seen = defaults.bool(forKey: DefaultsKey.hasSeenOnboarding)

This is a small improvement, but it pays off quickly as the number of settings grows.

Store Custom Data with Codable

UserDefaults does not store arbitrary custom structs directly, but you can encode them to Data first.

swift
1import Foundation
2
3struct Profile: Codable {
4    let name: String
5    let age: Int
6}
7
8let defaults = UserDefaults.standard
9let profile = Profile(name: "Ada", age: 30)
10
11let encoded = try JSONEncoder().encode(profile)
12defaults.set(encoded, forKey: "profile")
13
14if let savedData = defaults.data(forKey: "profile") {
15    let decoded = try JSONDecoder().decode(Profile.self, from: savedData)
16    print(decoded)
17}

This works well for small custom objects, but it is still not a substitute for a database or document store.

What Not to Put in UserDefaults

Avoid using UserDefaults for:

  • passwords or tokens
  • large caches
  • frequently changing large objects
  • relational or query-heavy data

Sensitive data belongs in Keychain. Large or structured app data belongs in a database, files, or another persistence layer.

UserDefaults is best when the value is small, simple, and read as application configuration rather than as core domain data.

Keep the API Simple

You do not usually need to call synchronize(). Modern Apple platforms handle persistence automatically. Writing values through UserDefaults.standard is enough for ordinary app code.

If your app grows, consider wrapping access in a small settings service or property wrapper so view controllers and models do not all talk to raw keys directly.

Common Pitfalls

  • Using UserDefaults for secrets that should be stored in Keychain.
  • Treating it like a database for large or complex app data.
  • Scattering literal string keys throughout the codebase.
  • Using object(forKey:) everywhere instead of typed getters.
  • Forgetting that missing values need sensible defaults on read.

Summary

  • Use UserDefaults for small, non-sensitive preferences and app flags.
  • Prefer typed getters and setters over generic object access.
  • Centralize keys so preference names stay consistent across the app.
  • Encode small Codable values to Data when you need lightweight custom storage.
  • Use Keychain or a fuller persistence layer when the data is sensitive, large, or highly structured.

Course illustration
Course illustration

All Rights Reserved.