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.
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.
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.
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.
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
UserDefaultsfor 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
UserDefaultsfor 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
Codablevalues toDatawhen you need lightweight custom storage. - Use Keychain or a fuller persistence layer when the data is sensitive, large, or highly structured.

