iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Storage

@ionic/storage-angular wraps IndexedDB and SQLite into a key/value API for persistent app state. Works offline, larger than localStorage, available on iOS / Android / Web.

Setup, key-value, indexes, encryption

EXAMPLE
// 1) Install (Angular)
// npm i @ionic/storage-angular
// For SQLite on native: npm i @ionic-enterprise/secure-storage  (paid)
// Or: ionic capacitor add ios; npm i @capacitor-community/sqlite

// 2) Register the module
// app.module.ts
import { IonicStorageModule } from '@ionic/storage-angular';
import { Drivers } from '@ionic/storage';
import { NgModule } from '@angular/core';

@NgModule({
    imports: [
        IonicStorageModule.forRoot({
            name:        '__myappdb',
            driverOrder: [Drivers.IndexedDB, Drivers.LocalStorage],
        }),
    ],
})
export class AppModule {}

// 3) Service wrapper
import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage-angular';

@Injectable({ providedIn: 'root' })
export class StorageService {
    private _store: Storage | null = null;

    constructor(private storage: Storage) {}

    async init() {
        this._store = await this.storage.create();
    }

    async set(key: string, value: unknown) {
        await this._store!.set(key, value);
    }

    async get<T>(key: string): Promise<T | null> {
        return this._store!.get(key);
    }

    async remove(key: string) { return this._store!.remove(key); }
    async clear()              { return this._store!.clear(); }

    async keys(): Promise<string[]> { return this._store!.keys(); }

    async forEach(fn: (value: unknown, key: string) => void) {
        return this._store!.forEach(fn);
    }
}

// 4) Bootstrap before APP_INITIALIZER
// providers: [
//   { provide: APP_INITIALIZER, multi: true, useFactory: (s: StorageService) => () => s.init(), deps: [StorageService] },
// ]

// 5) Use it
await this.storage.set('user', { id: 42, name: 'Ada' });
const user = await this.storage.get<User>('user');

// 6) Common patterns

// Auth token persistence
await this.storage.set('auth_token', token);
const saved = await this.storage.get<string>('auth_token');
if (saved) httpInterceptor.attach(saved);

// Offline cache
await this.storage.set(`feed:${userId}`, posts);
const cached = await this.storage.get<Post[]>(`feed:${userId}`);
if (cached) showImmediately(cached);
await refetch();

// Settings
await this.storage.set('settings', { theme: 'dark', fontSize: 16 });

// 7) When you need queries / large data — switch to SQLite
import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite';
const sqlite = new SQLiteConnection(CapacitorSQLite);
const db = await sqlite.createConnection('myapp', false, 'no-encryption', 1, false);
await db.open();
await db.execute(`CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY, body TEXT, ts INTEGER)`);
await db.run('INSERT INTO messages (body, ts) VALUES (?, ?)', ['hello', Date.now()]);
const { values } = await db.query('SELECT * FROM messages ORDER BY ts DESC LIMIT 50');

// 8) Encrypted storage (sensitive data)
// For tokens / health data: Capacitor's Secure Storage plugin (uses Keychain / KeyStore)
import { SecureStorage } from '@aparajita/capacitor-secure-storage';
await SecureStorage.set('auth_token', token, true /* sync to iCloud Keychain */);
const t = await SecureStorage.get('auth_token');

// 9) Don't use it for
//   • Files / images → Filesystem API (Capacitor)
//   • Large blobs → IndexedDB directly via idb-keyval
//   • Cross-device sync → Firebase / Supabase / your backend

// 10) Best practices
//   • Initialise once at app start (APP_INITIALIZER)
//   • Wrap in a typed service so call sites don't sprinkle string keys
//   • Encrypt sensitive values
//   • Migrate schema on app upgrade (versioned keys)

Why it matters

Use Ionic Storage for app settings + small caches; reach for SQLite (Capacitor plugin) when you need queries; use Secure Storage for tokens. Different needs, different layers — don’t use localStorage for production iOS / Android apps (it gets cleared).

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import { Preferences } from '@capacitor/preferences';
await Preferences.set({ key: 'token', value: 't0k3n' });
const { value } = await Preferences.get({ key: 'token' });
Try it Yourself »

Exercise

Capacitor key/value plugin.

import { } from '@capacitor/preferences';

Discussion

Loading…