options.namespace - Namespace Prefix Configuration
Quick Start (30 seconds)
const userState = state({ name: 'Alice' });
// Without namespace - key stored as 'userData'
autoSave(userState, 'userData');
// With namespace - key stored as 'myApp:userData'
autoSave(userState, 'userData', {
namespace: 'myApp'
});
// Multiple apps can coexist safely!
autoSave(userState, 'settings', { namespace: 'myApp' });
autoSave(userState, 'settings', { namespace: 'otherApp' });
// 'myApp:settings' and 'otherApp:settings' don't conflict ✨What just happened? You added a prefix to your storage keys to prevent naming conflicts!
What is options.namespace?
options.namespace is a configuration option that adds a prefix to all storage keys to organize and isolate your app's data.
Simply put: it's like having your own folder in a shared filing cabinet. Your data stays separate from everyone else's.
Think of it as putting your app's name on all your stuff so it doesn't get mixed up with others.
Syntax
autoSave(state, key, {
namespace: string
})Value:
- Any string (typically your app name)
- Becomes a prefix:
namespace:key
Default: '' (empty string - no namespace)
Why Does This Exist?
The Problem: Storage Key Collisions
Without namespaces, different apps/libraries can overwrite each other's data:
// Your app
const userState = state({ name: 'Alice' });
autoSave(userState, 'settings');
// Stores as 'settings' in localStorage
// Another library also uses 'settings'
someLibrary.saveSettings({ theme: 'dark' });
// Overwrites your 'settings'! ❌
// Your app's settings are gone!
console.log(localStorage.getItem('settings'));
// Shows library's data, not yours ❌What's the Real Issue?
Multiple apps/libraries
|
v
Use same key names
|
v
Last write wins
|
v
Data loss! ❌Problems: ❌ Key collisions - Different apps use same keys
❌ Data loss - One app overwrites another's data
❌ No isolation - Can't tell which data belongs to whom
❌ Hard to debug - Mysterious data corruption
The Solution with options.namespace
// Your app
const userState = state({ name: 'Alice' });
autoSave(userState, 'settings', {
namespace: 'myApp'
});
// Stores as 'myApp:settings'
// Another library
someLibrary.saveSettings({ theme: 'dark' });
// Stores as 'settings' (or 'otherApp:settings')
// No conflict! Both coexist safely ✅
console.log(localStorage.getItem('myApp:settings')); // Your data
console.log(localStorage.getItem('settings')); // Library's dataWhat Just Happened?
Add namespace prefix
|
v
'settings' → 'myApp:settings'
|
v
Each app has its own space
|
v
No collisions! ✅Benefits: ✅ Prevents collisions - Each namespace is isolated
✅ Clean organization - Easy to see what belongs to your app
✅ Safe to use common names - 'settings', 'data', 'user' etc.
✅ Easy cleanup - Clear all keys with specific prefix
Mental Model
Think of localStorage without namespaces as a messy shared drawer:
No Namespace (Shared Drawer)
┌─────────────────────┐
│ settings (yours?) │
│ user (theirs?) │
│ data (mine?) │
│ config (?) │
│ │
│ Everything mixed! │
│ Who owns what? ❌ │
└─────────────────────┘Think of namespaces as labeled folders:
With Namespace (Organized Folders)
┌─────────────────────┐
│ myApp: │
│ ├─ settings │
│ ├─ user │
│ └─ data │
│ │
│ otherApp: │
│ ├─ settings │
│ └─ config │
│ │
│ Everything clear ✅│
└─────────────────────┘Key Insight: Namespaces give your app its own labeled space in shared storage.
How Does It Work?
When you specify a namespace, autoSave prefixes all storage keys:
Step-by-Step Process
1️⃣ Configuration
autoSave(state, 'userData', {
namespace: 'myApp'
});2️⃣ Key Transformation
Original key: 'userData'
|
v
Add namespace prefix
|
v
Final key: 'myApp:userData'
|
v
Store with prefixed key3️⃣ Storage Operations
Save:
localStorage.setItem('myApp:userData', json)
Load:
localStorage.getItem('myApp:userData')
Remove:
localStorage.removeItem('myApp:userData')4️⃣ Key Listing
Get all keys:
|
v
Filter by namespace
|
v
Return only 'myApp:*' keys
|
v
Strip prefix for displayBasic Usage
Example 1: Single Namespace
const state1 = state({ count: 0 });
const state2 = state({ name: 'Alice' });
// All your app's data under 'myApp'
autoSave(state1, 'counter', { namespace: 'myApp' });
autoSave(state2, 'user', { namespace: 'myApp' });
// Storage:
// 'myApp:counter' → { count: 0 }
// 'myApp:user' → { name: 'Alice' }Example 2: Multiple Namespaces
// Main app data
const appState = state({ theme: 'dark' });
autoSave(appState, 'settings', { namespace: 'app' });
// Plugin data
const pluginState = state({ enabled: true });
autoSave(pluginState, 'settings', { namespace: 'plugin' });
// Storage:
// 'app:settings' → { theme: 'dark' }
// 'plugin:settings' → { enabled: true }
// No conflict!Example 3: No Namespace (Global)
const globalState = state({ apiUrl: 'https://api.example.com' });
// No namespace - stored as-is
autoSave(globalState, 'config');
// Storage:
// 'config' → { apiUrl: '...' }Real-World Examples
Example 1: Multi-Tenant Application
// Each customer gets their own namespace
function createCustomerData(customerId) {
const customerState = state({
name: '',
preferences: {}
});
autoSave(customerState, 'data', {
namespace: `customer_${customerId}`
});
return customerState;
}
// Customer A
const customerA = createCustomerData('123');
// Stores as 'customer_123:data'
// Customer B
const customerB = createCustomerData('456');
// Stores as 'customer_456:data'
// Data isolated per customer ✨Example 2: Plugin System
// Core app
const coreState = state({ version: '1.0' });
autoSave(coreState, 'app', { namespace: 'core' });
// Plugin 1
const plugin1State = state({ enabled: true });
autoSave(plugin1State, 'config', { namespace: 'plugin1' });
// Plugin 2
const plugin2State = state({ theme: 'custom' });
autoSave(plugin2State, 'config', { namespace: 'plugin2' });
// Each plugin isolated:
// 'core:app'
// 'plugin1:config'
// 'plugin2:config'Example 3: Environment-Based Namespaces
const env = process.env.NODE_ENV; // 'development' or 'production'
const appState = state({ settings: {} });
autoSave(appState, 'data', {
namespace: `myApp_${env}`
});
// Development: 'myApp_development:data'
// Production: 'myApp_production:data'
// No conflict between environments!Example 4: Version-Based Namespaces
const APP_VERSION = '2.0';
const userState = state({ preferences: {} });
autoSave(userState, 'user', {
namespace: `myApp_v${APP_VERSION}`
});
// 'myApp_v2.0:user'
// When you update to v3.0:
// Old data: 'myApp_v2.0:user'
// New data: 'myApp_v3.0:user'
// Can migrate or start fresh!Example 5: Clear Namespace
// Utility to clear all data in a namespace
function clearNamespace(namespace) {
const prefix = `${namespace}:`;
const keysToRemove = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key && key.startsWith(prefix)) {
keysToRemove.push(key);
}
}
keysToRemove.forEach(key => localStorage.removeItem(key));
console.log(`Cleared ${keysToRemove.length} keys from ${namespace}`);
}
// Usage
clearNamespace('myApp');
// Removes all 'myApp:*' keysCommon Patterns
Pattern 1: App-Wide Namespace
const APP_NAMESPACE = 'myApp';
function createSavedState(key, initialData) {
const stateObj = state(initialData);
autoSave(stateObj, key, { namespace: APP_NAMESPACE });
return stateObj;
}
// Use throughout app
const user = createSavedState('user', { name: '' });
const settings = createSavedState('settings', { theme: 'light' });Pattern 2: User-Specific Namespace
function getUserNamespace(userId) {
return `user_${userId}`;
}
function saveUserData(userId, data) {
const userState = state(data);
autoSave(userState, 'data', {
namespace: getUserNamespace(userId)
});
return userState;
}
// Different users, isolated data
saveUserData('alice', { preferences: {} });
saveUserData('bob', { preferences: {} });Pattern 3: Feature Namespaces
const namespaces = {
auth: 'auth',
cart: 'shopping',
settings: 'preferences'
};
// Auth data
const authState = state({ token: '' });
autoSave(authState, 'session', { namespace: namespaces.auth });
// Cart data
const cartState = state({ items: [] });
autoSave(cartState, 'data', { namespace: namespaces.cart });Pattern 4: Nested Namespaces
function createNestedNamespace(...parts) {
return parts.join(':');
}
const namespace = createNestedNamespace('myApp', 'user', '123');
// 'myApp:user:123'
const userData = state({ name: 'Alice' });
autoSave(userData, 'profile', { namespace });
// Stores as 'myApp:user:123:profile'Pattern 5: Debug Namespace
const namespace = process.env.NODE_ENV === 'development'
? 'myApp_dev'
: 'myApp';
// Development: 'myApp_dev:*'
// Production: 'myApp:*'
// Can safely test without affecting production dataPattern 6: List All Namespace Keys
function listNamespaceKeys(namespace) {
const prefix = `${namespace}:`;
const keys = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key && key.startsWith(prefix)) {
keys.push(key.replace(prefix, ''));
}
}
return keys;
}
const appKeys = listNamespaceKeys('myApp');
console.log('App storage keys:', appKeys);
// ['user', 'settings', 'cache']Summary
What is options.namespace?
A configuration option that adds a prefix to all storage keys to organize and isolate your app's data from other apps and libraries.
Why use it?
- ✅ Prevents key name collisions
- ✅ Organizes storage by app/feature
- ✅ Enables safe use of common key names
- ✅ Makes bulk operations easier (clear all app data)
- ✅ Supports multi-tenant applications
Key Takeaway:
Without Namespace With Namespace
| |
'settings' 'myApp:settings'
| |
Name collisions Isolated space
| |
Conflicts ❌ Safe storage ✅One-Line Rule: Always use a namespace to give your app its own labeled space in storage.
Best Practices:
- Use your app name as namespace:
'myApp' - Keep namespaces short and lowercase
- Use consistent naming across your app
- Consider environment-specific namespaces for development
Remember: Namespace everything to avoid storage chaos! 🎉