UserDefaults, Keychain, files, SQLite, Core Data or SwiftData: how do you choose, and what survives deletion, reinstall and backup?

13.1.1 · L2 · Interview

Predict first

A download that can be fetched again was stored in Documents. What is the cost, and where should it be?

// A: nothing, Documents is always the right place
// B: it is backed up and counts against the user’s backup, so it belongs in Caches (or is excluded from backup)
// C: it is deleted on every launch
  • A
  • B
  • C

Mental model. Think of luggage: valuables go in the hotel safe (Keychain), clothes in the suitcase (files, database), and the free sample soaps in the bag the cleaners may throw away (Caches). Check what happens to each if you change hotels.

Start with what the data is. Preferences and small flags (a theme, the last tab) go to UserDefaults (a property list in the app container; fast and simple, but not for large or secret data). Secrets (passwords, tokens, keys) go to the Keychain, which is encrypted and access-controlled. Documents and blobs (a user’s photo, a downloaded file) go to files in the right directory. Structured, queryable or related records (messages, a to-do list with tags) go to a database: SQLite directly, Core Data, SwiftData or a library such as GRDB. Rebuildable data (decoded thumbnails, network responses) goes in Caches and must tolerate being deleted. The directory-by-directory rules and safe writes are covered in the Foundation topic; the question here is the container.

Then ask what survives what. Delete the app: the app container (Documents, Library, UserDefaults, SQLite files) is removed, but Keychain items usually remain and reappear on reinstall (which is why “is this a first launch?” based on the Keychain misleads, and why a sign-out-on-uninstall rule needs an explicit flag). Backup and restore (iCloud or an encrypted local backup): Documents and Application Support and UserDefaults are included, Caches and tmp are not, and Keychain items come back on a new device only if they are not marked …ThisDeviceOnly (such items are never restored to another device). Low storage: the system may purge Caches (and tmp). App update: all of it persists, so the schema must be migrated. Choose by lifetime: a token must survive relaunch but not leak into backups (Keychain, ThisDeviceOnly if needed); a download that can be fetched again must be in Caches or marked excluded from backup; user-created content must be backed up and must never live only in Caches. Also mind who else needs it: an extension or widget needs an app-group container or a shared keychain access group; multi-device needs a sync story from the start; and anything personal falls under the privacy rules (minimise what you keep, and delete on sign-out).

Documents is backed up. Rebuildable data should live in Caches, or be excluded from backup, so it does not bloat backups.

Best forSurvives app deletionRestored from backupEncrypted
UserDefaultssmall preferencesnoyesno (plain plist)
Keychainsecrets, tokens, keysusually yesyes, unless ThisDeviceOnlyyes
Files (Documents)user documents, blobsnoyesby file protection class
Caches / tmprebuildable datanonoby file protection class
Database (SQLite, Core Data, SwiftData)structured, related, queryable datanoyesby file protection class

Common traps

  • Putting secrets or large blobs in UserDefaults. It is a plain, unencrypted plist read into memory.
  • Using the Keychain to detect a fresh install. Keychain items survive uninstall, so you see “returning user” state on a clean install.

They might follow up with

  • Which directories are backed up? Documents and Application Support; not Caches or tmp.
  • Where does a re-downloadable 200 MB file go? Caches, or Application Support marked excluded from backup.

Related questions

  • 13.1.2 How does the Keychain work, how do you add, read and update an item, and what do accessibility classes and…
  • 13.5.1 What is the repository pattern, and why map storage models to domain models?
  • 2.3.6 Where should an iOS app put files: Documents, Application Support, Caches or tmp?

How does the Keychain work, how do you add, read and update an item… →