Skip to main content

Configuration

Strata Storage provides extensive configuration options to customize behavior for your specific needs.

Configuration Overview

import { Strata } from 'strata-storage';

const storage = new Strata({
// Platform detection (auto-detected by default)
platform: 'web', // 'web' | 'ios' | 'android' | 'node'

// Default storage types in order of preference
defaultStorages: ['indexedDB', 'localStorage', 'memory'],

// Storage adapter specific configurations
adapters: {
indexedDB: {
dbName: 'MyAppDB',
version: 1
},
localStorage: {
prefix: 'myapp_'
},
cookies: {
secure: true,
sameSite: 'strict'
}
},

// Encryption settings
encryption: {
enabled: false,
password: 'your-secure-password',
algorithm: 'AES-GCM',
keyLength: 256,
keyDerivation: 'PBKDF2'
},

// Compression settings
compression: {
enabled: false,
algorithm: 'lz', // the only supported algorithm
threshold: 1024 // bytes
},

// Synchronization settings
sync: {
enabled: false,
storages: ['localStorage'],
conflictResolution: 'latest'
},

// Time-to-live settings
ttl: {
defaultTTL: 3600000, // 1 hour (ms)
cleanupInterval: 60000, // 1 minute
autoCleanup: true
}
});

Configuration Options

Platform

Strata automatically detects the platform, but you can override it:

const storage = new Strata({
platform: 'ios' // Force iOS behavior
});

Options:

  • 'web' - Browser environment
  • 'ios' - iOS native (Capacitor)
  • 'android' - Android native (Capacitor)
  • 'node' - Node.js environment

Default Storages

Specify storage preference order. Strata will use the first available:

const storage = new Strata({
defaultStorages: ['sqlite', 'preferences', 'memory']
});

Web Options:

  • 'memory' - In-memory storage
  • 'localStorage' - Browser localStorage
  • 'sessionStorage' - Browser sessionStorage
  • 'indexedDB' - IndexedDB database
  • 'cookies' - HTTP cookies
  • 'cache' - Cache API

Mobile Options:

  • 'preferences' - Native preferences (UserDefaults/SharedPreferences)
  • 'sqlite' - SQLite database
  • 'secure' - Keychain (iOS) / EncryptedSharedPreferences (Android)
  • 'filesystem' - File system storage

Adapter Configuration

IndexedDB

adapters: {
indexedDB: {
dbName: 'MyDatabase', // Database name
version: 1 // Database version
}
}

LocalStorage/SessionStorage

adapters: {
localStorage: {
prefix: 'app_' // Key prefix
}
}

Cookies

adapters: {
cookies: {
secure: true, // HTTPS only
sameSite: 'lax' // 'strict' | 'lax' | 'none'
}
}

SQLite (Mobile)

adapters: {
sqlite: {
filename: 'app.db' // Database file name
}
}

The native SQLite backend also accepts per-call database / table options (passed to get/set/etc.) to address multiple physical stores — see the SQLite adapter reference.

Encryption Configuration

encryption: {
enabled: true, // Enable/disable encryption
password: 'secret', // Encryption password
algorithm: 'AES-GCM', // 'AES-GCM' | 'AES-CBC'
keyLength: 256, // 128 | 192 | 256
keyDerivation: 'PBKDF2', // PBKDF2
iterations: 600000, // PBKDF2 iterations (default: 600000, OWASP)
saltLength: 16 // Salt length in bytes
}

Compression Configuration

compression: {
enabled: true, // Enable/disable compression
algorithm: 'lz', // only the bundled zero-dependency LZ codec is supported
threshold: 1024 // Min size to compress (bytes)
}

Sync Configuration

sync: {
enabled: true, // Enable cross-tab sync
storages: ['localStorage'], // Storages to sync (cross-tab fallback is localStorage-only)
interval: 5000, // Optional periodic sync interval (ms)
conflictResolution: 'latest' // 'latest' | 'merge' | custom function
}

Cross-tab sync uses BroadcastChannel when available and falls back to storage events. Browsers only fire cross-tab storage events for localStorage; sessionStorage is tab-scoped and never propagates cross-tab.

TTL Configuration

ttl: {
defaultTTL: 3600000, // Default TTL in ms (1 hour)
cleanupInterval: 60000, // Cleanup sweep interval (ms)
autoCleanup: true, // Auto-remove expired items
batchSize: 100, // Max items removed per cleanup cycle
slidingTTL: false, // Reset TTL on access (instance default)
onExpire: (keys) => {} // Callback invoked with expired keys
}

Environment-Specific Configuration

Development

const devConfig = {
encryption: { enabled: false }, // Disable for debugging
compression: { enabled: false },
sync: {
enabled: true,
interval: 0 // 0 = event-driven (no polling)
}
};

Production

const prodConfig = {
encryption: {
enabled: true,
password: process.env.STORAGE_KEY
},
compression: {
enabled: true,
threshold: 512 // Aggressive compression
},
ttl: {
autoCleanup: true,
cleanupInterval: 300000 // 5 minutes
}
};

Storage Selection

Strata does not use named "strategies." Instead, list the storage backends you want in defaultStorages, in order of preference — Strata uses the first one available on the current platform:

const storage = new Strata({
// Try persistent stores first, fall back to memory as a last resort
defaultStorages: ['indexedDB', 'localStorage', 'memory']
});
danger
defaultStorages is not a registration list

It is the preference order for choosing the default adapter, and the fallback order when one is unusable. Operations with no explicit storagekeys(), clear(), size(), subscribe() — deliberately span every registered adapter, so listing one storage here does not stop the others from being registered or swept.

To leave an adapter out entirely, say so:

const storage = defineStorage({
defaultStorages: ['localStorage'],
adapters: { sessionStorage: false, indexedDB: false, cookies: false, cache: false },
});

Since 2.9.0, adapters: { <name>: false } skips registration, not just initialization. (Before 2.9.0 it only skipped initialization, so the adapter was still registered and still swept — which is what made defaultStorages look like a registration list that was being ignored.)

Key prefix and the 3.0.0 migration

Since 3.0.0, localStorage and sessionStorage keys are written under strata: (DEFAULT_WEB_KEY_PREFIX, exported). Existing data migrates itself on read.

const storage = defineStorage(); // keys at `strata:<key>`
const legacy = defineStorage({ keyPrefix: false }); // pre-3.0, bare keys
const custom = defineStorage({ keyPrefix: 'myapp:' }); // your own
const noMove = defineStorage({ migrateLegacyKeys: false }); // don't adopt 2.x entries
danger
Take keyPrefix: false when something outside this library reads a physical key

A pre-paint theme script that runs before any module loads, or a logger reading its own level, knows the exact key name — and a prefix changes it underneath them. Migration keeps the data reachable through this library; it cannot fix a hard-coded reader.

How migration works. A miss at strata:<key> falls back to the bare <key>; if the value is one of ours it is moved under the prefix and returned. It is per key, on read — never a bulk sweep, which would adopt every unprefixed envelope on the origin including keys belonging to an instance that opted out or a sibling app still on 2.x. It never adopts a non-envelope, and it never overwrites a value already at the prefixed key. keys() lists not-yet-migrated entries so enumeration stays complete, but listing never moves anything.

Unchanged: cookies (already strata_), indexedDB and cache (named stores), memory (its own Map), url (already prefixes its params). namespace is a separate mechanism — the physical key is <keyPrefix><namespace>:<key>.

Shared storage areas and key ownership

localStorage, sessionStorage and cookies are shared with every other script on the origin, and the web adapters' key prefix is empty by default. Since 2.9.0 an adapter identifies its own data by shape — a key is its own only when the stored value is a StorageValue envelope — so keys(), the TTL sweep and clear() never touch data this library did not write.

Consequences worth knowing:

  • A key written to the same area by anything else is invisible to keys() by design.
  • A value we cannot read is skipped and reported at debug, not as an error: it is evidence the key belongs to somebody else, which is the ordinary case in a shared area.
  • setLogLevel('debug') (exported) names every skipped key and why.

Setting namespace or a per-adapter prefix is still worth doing for a clean keyspace. It is no longer what keeps this library off other applications' keys.

Custom Configuration Patterns

Multi-Instance Configuration

// User data storage
const userStorage = new Strata({
defaultStorages: ['secure', 'preferences'],
encryption: { enabled: true }
});

// Cache storage
const cacheStorage = new Strata({
defaultStorages: ['cache', 'indexedDB'],
ttl: { defaultTTL: 300000 } // 5 minutes
});

// Temporary storage
const tempStorage = new Strata({
defaultStorages: ['memory', 'sessionStorage'],
ttl: { defaultTTL: 60000 } // 1 minute
});

Feature Flags

const storage = new Strata({
// Enable features based on environment
encryption: {
enabled: process.env.NODE_ENV === 'production'
},
compression: {
enabled: !navigator.connection?.saveData
},
sync: {
enabled: 'BroadcastChannel' in window
}
});

Validation

Strata validates configuration at initialization:

try {
const storage = new Strata({
encryption: {
enabled: true
// Missing required 'password'
}
});
await storage.initialize();
} catch (error) {
console.error('Invalid configuration:', error);
}

Next Steps