DEV Community

Cover image for Persisting RN Settings Across Reinstalls Without User Accounts
Adil Mezghouti
Adil Mezghouti

Posted on

Persisting RN Settings Across Reinstalls Without User Accounts

A while back, I worked on a React Native app that had no support for user sign-ups or accounts. Despite that, we had a clear requirement: preserve user customizations across app installs.
Users needed their custom theme choices, language/locale settings, and favorited items to survive if they deleted and reinstalled the app. Furthermore, we needed to keep their anonymous analytics IDs persistent so we wouldn't pollute our data pipeline with "duplicate" new users every time someone reinstalled.

Without a backend database or user ID to attach data to, I solved this by leveraging @react-native-async-storage/async-storage alongside the built-in native OS backup mechanisms (iCloud on iOS and Google Auto Backup on Android). Here is how it works, what to watch out for, and how to set it up.

1. Requirements, Constraints & User Cost

Before relying on native backups, you need to be aware of how the OS handles state restoration:

  • Device Backup Prerequisite: This strategy relies on the user having OS-level backups toggled on (Settings > Apple Account > iCloud Backup on iOS or Settings > Google > Backup on Android). If a user turns this off, state resets on reinstall.
  • Zero Cost for Users: Users do not need paid cloud storage tiers:
    • Android: Google Auto Backup gives up to 25 MB per app for free—and it is completely exempt from the user's 15 GB personal Google Drive quota.
    • iOS: Settings payloads are tiny JSON files (< 100 KB) that consume virtually zero space in Apple's free 5 GB iCloud tier.
  • Security & Latency Guardrails: Never store sensitive tokens or credentials in AsyncStorage backup files (use Keychain/KeyStore instead). Also, keep in mind that OS cloud snapshots trigger asynchronously (usually on Wi-Fi while charging). An immediate reinstall seconds after a setting change might restore the previous snapshot.

2. Code Implementation

Instead of cluttering storage with isolated keys, consolidate your guest preferences and anonymous analytics ID into a single schema.

import AsyncStorage from '@react-native-async-storage/async-storage';

export interface GuestAppState {
  analyticsId: string;
  settings: {
    theme: 'light' | 'dark' | 'system';
    locale: string;
  };
  favorites: string[]; // Array of favorited item IDs
}

const STORAGE_KEY = '@app_guest_state_v1';

export const saveGuestState = async (state: GuestAppState): Promise<void> => {
  try {
    await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(state));
  } catch (error) {
    console.error('Failed to persist guest state:', error);
  }
};

export const loadGuestState = async (): Promise<GuestAppState | null> => {
  try {
    const raw = await AsyncStorage.getItem(STORAGE_KEY);
    return raw ? JSON.parse(raw) : null;
  } catch (error) {
    console.error('Failed to hydrate guest state:', error);
    return null;
  }
};
Enter fullscreen mode Exit fullscreen mode

How It Works Under the Hood

When a user reinstalls the app:

  1. AsyncStorage writes keys to standard internal storage locations (iOS Documents directory / Android internal SQLite/Key-Value files).
  2. The native OS includes these files in its scheduled cloud snapshot.
  3. Upon reinstalling, the OS restores the application sandbox files before the React Native JavaScript bundle executes its initial boot.
  4. When your app mounts, loadGuestState() reads the restored JSON file as if the app was never uninstalled—preserving theme, favorites, and the original analyticsId.

3. Essential Native Configuration

For native backups to work smoothly across installations, you need a few minor native file configurations.

Android Setup (android/app/src/main)

Ensure android:allowBackup="true" is set in AndroidManifest.xml:

<!-- AndroidManifest.xml -->
<application
    android:allowBackup="true"
    android:fullBackupContent="@xml/backup_rules"
    android:dataExtractionRules="@xml/data_extraction_rules">
    <!-- ... -->
</application>
Enter fullscreen mode Exit fullscreen mode

Define explicit rules in res/xml/data_extraction_rules.xml (for Android 12+) to ensure AsyncStorage databases and shared preferences are backed up:

<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules>
    <cloud-backup>
        <include domain="sharedpref" path="." />
        <include domain="database" path="." />
    </cloud-backup>
</data-extraction-rules>
Enter fullscreen mode Exit fullscreen mode

iOS Setup

iOS automatically backs up the app's Documents directory to iCloud by default. No Xcode configuration is required unless you manually flag files using NSURLIsExcludedFromBackupKey.

Wrap-Up

Relying on native OS cloud backups for AsyncStorage is an effective way to preserve user customizations in accountless React Native apps. You keep user preferences intact, avoid backend infrastructure costs, maintain accurate analytics identity, and never cost your users a dime in cloud storage fees.

Top comments (0)