Local-first data

Where does an app's local data live on a phone?

An app's local data lives in a private area of storage that the operating system gives to that app, a sandboxed data container on iOS and app-specific internal storage on Android. Files, preferences and databases go there, while keys and other small secrets belong in the platform's key store, the Keychain on iOS and the Android Keystore on Android.

Learning objectives

After reading this article you will be able to:

  • Identify where Android and iOS keep an app's private files and databases
  • Explain why a local-first app's only copy must never sit in a cache
  • Describe how key stores, encryption at rest and backups treat app data

The app’s private storage

Both mobile platforms give each app its own area of storage that other apps cannot reach.

On Android, this is app-specific storage. Its internal directories hold a location for persistent files and another for cache data. Android’s documentation says the system prevents other apps from accessing these locations, and on Android 10 and higher they are encrypted. When the user uninstalls the app, files in app-specific storage are removed, so Google advises against keeping anything there that the user expects to outlive the app.

On iOS, an app works inside a sandbox. At installation, the system creates container directories for the app: a bundle container that holds the signed app itself and cannot be written to, and a data container for the app’s and the user’s data. Inside the data container the main directories are:

  • Documents/ for user-generated content, which can be exposed to the user through file sharing.
  • Library/Application Support/ for files the app needs to run but that should stay hidden.
  • Library/Caches/ for data the app can recreate.
  • tmp/ for files that do not need to persist between launches.

Files, preferences and databases

Within that private area, apps choose a format. Android’s overview lists key-value preferences for small private values and a private database for structured data, using the Room persistence library. Its backup documentation lists the app’s database directory, including files created with SQLiteOpenHelper, among the files it backs up.

A local-first app needs storage that survives restarts and handles frequent small writes. That points to a database or to files in the persistent directories, not to caches.

Caches can disappear

Not every app directory is permanent. Android’s documentation warns that when a device is low on internal storage, the system may delete cache files to recover space. Apple’s guide says the system may purge tmp/ when the app is not running.

The lesson for local-first apps is direct. If the device is the source of truth, the only copy of a person’s work must never sit in a cache directory.

Keys and secrets live somewhere else

Encryption keys, tokens and identity secrets go into a dedicated store, not into ordinary files.

  • The Android Keystore keeps key material out of the app’s process: the app asks a system process to sign or decrypt, and the key cannot be exported. Keys can also be bound to secure hardware such as a Trusted Execution Environment or Secure Element, where supported.
  • The iOS Keychain is a single SQLite database managed by a system daemon, securityd, which decides which items each app can access. Items are encrypted, and each has an accessibility class similar to file Data Protection. Items marked “this device only” are protected so they are useless if restored to a different device.

Keychain items do not always follow the app’s lifecycle. Offline Protocol’s security notes give one case to plan for: on iOS, Keychain identity state survives uninstall unless explicitly wiped, so identity deletion belongs in the account lifecycle.

Encryption at rest

Phones encrypt app data on the device, but the details differ. On iOS, every file has a Data Protection class. The default for third-party app data is Protected Until First User Authentication, which keeps data readable once the user has entered their passcode after a restart, even while the phone is locked. The stricter Complete Protection class discards its key shortly after the device locks, so the app cannot read those files until the user enters the passcode or uses Face ID or Touch ID again.

That choice matters for apps that sync in the background: a file the app needs while locked cannot use the strictest class. The article on encryption at rest versus in transit covers the wider picture.

Backups copy it off the phone

Local data does not always stay local.

  • Android’s Auto Backup includes shared preferences, files in the app’s internal storage, its database directory and its app-specific external files by default. It excludes cache, code cache and no-backup directories. Each app can store up to 25 MB, and Google says the backup is end-to-end encrypted on Android 9 or higher using the device’s PIN, pattern or password. Apps can opt out or exclude files.
  • On iOS, files in Documents/ and Application Support/ are backed up by default, and Apple’s guide says files that can be re-created or downloaded should be excluded using the NSURLIsExcludedFromBackupKey resource value. Library/Caches/ and tmp/ are not backed up.

A backup is one more copy of the data, with its own location, encryption and retention, so it belongs in the same plan as every other copy.

Sources

Build it with Offline Protocol

Offline Protocol's security page explains that identity secrets and persisted protocol state use separate storage roles, and what to wipe when an account ends. It also covers plaintext control traffic and the threat model.

Read the security page