Persisting Key‑Value Data with Capacitor Storage Plugin
Learn how to persist key‑value data across app launches with Capacitor's Storage plugin, including installation, a TypeScript wrapper, verification steps, and limits.
29 Mar 2026, 15:46 UTC

Use Capacitor Storage to keep simple data across launches
\nWhen you need to remember a user preference, a token, or any small piece of state between app starts, the Capacitor @capacitor/storage plugin provides a cross‑platform API that writes to SharedPreferences on Android, NSUserDefaults on iOS, and falls back to localStorage on the web.
Install and sync the plugin
\n# Run in the project root\nnpm i @capacitor/storage\nnpx cap sync\n\nNo special permissions are required; the command adds the plugin to native projects and copies the web assets.
\nBasic TypeScript wrapper
\nimport { Storage } from '@capacitor/storage';\n\n/** Store any JSON‑serializable value */\nexport async function setItem(key: string, value: unknown): Promise {\n await Storage.set({\n key,\n value: JSON.stringify(value)\n });\n}\n\n/** Retrieve and parse the stored value */\nexport async function getItem(key: string): Promise {\n const ret = await Storage.get({ key });\n return ret.value ? (JSON.parse(ret.value) as T) : null;\n}\n\nThe wrapper converts objects to strings before calling Storage.set and parses them back on Storage.get. If the key does not exist, getItem returns null.
Where to call the functions
\nMake sure Capacitor is fully initialized before invoking the storage methods. In an Ionic/Angular app you can place the calls inside ngOnInit or after the platform.ready() promise resolves. Calling them too early (e.g., in a script that runs before the deviceready event) throws an error.
Verification steps
\n- \n
- Build and run the app on a physical device or emulator (
npx cap run androidorios). \n - Invoke
setItem('test-key', { foo: 42 })from a button or console. \n - Close the app completely (swipe away from recent tasks or stop the emulator). \n
- Relaunch the app and call
getItem('test-key'). \n - The returned object should equal
{ foo: 42 }. \n
You can also inspect the native storage directly:
\n- \n
- Android: open
/data/data//shared_prefs/.xmlin Device File Explorer; the key‑value pair appears as a string entry. \n - iOS: run the app in Xcode, then in the console execute
print(UserDefaults.standard.dictionaryRepresentation())and look for the key. \n
Limits and common mistakes
\n- \n
- String‑only storage: The plugin stores everything as a UTF‑8 string; objects must be serialized with
JSON.stringify. Forgetting to parse results in a string that contains the JSON text, e.g., '{ foo: 42 }' instead of an object. \n - Size quota: Each platform imposes a limit (typically a few megabytes). Storing large blobs or media files will silently fail or throw a quota‑exceeded error; use the
@capacitor/filesystemplugin for those cases. \n - Plain‑text data: Values are not encrypted. Do not store authentication tokens, passwords, or other secrets; consider using a secure storage solution such as
@capacitor-community/secure-storage. \n - Calling before ready: If you invoke
Storage.getorStorage.setbefore Capacitor finishes initializing (e.g., in the main HTML script), the promise rejects withPlugin not found. Guard the call withawait Capacitor.isPluginAvailable('Storage')or wait forplatform.ready(). \n - Data loss on reinstall: Clearing app data or uninstalling removes all entries. Treat the storage as a cache, not a permanent database. \n
When to choose Storage vs. other plugins
\nUse Capacitor Storage for simple preference‑style data (flags, counters, small JSON objects). For larger files, binary data, or hierarchical storage, prefer the Filesystem plugin. For encrypted credentials, look at community secure‑storage plugins.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.