Basic Usage
// Save
api.storage.set('my-key', { count: 42, items: ['a', 'b'] });
// Load
const data = api.storage.get('my-key');
// → { count: 42, items: ['a', 'b'] }
// Delete
api.storage.remove('my-key');
Plugin-Scoped Storage (Recommended)
Use getForPlugin and setForPlugin to automatically namespace your keys:
// Automatically stored under "plugin:my-plugin:theme"
api.storage.setForPlugin(meta.id, 'theme', 'dark');
const theme = api.storage.getForPlugin(meta.id, 'theme');
// → "dark"
This prevents key collisions between plugins without manual prefixing.
Common Patterns
Saving Element Positions
let currentApi = null;
export function setup(api) {
currentApi = api;
const container = api.container;
// Restore position
const pos = api.storage.getForPlugin(meta.id, 'pos');
if (pos) {
container.style.left = pos.left + 'px';
container.style.top = pos.top + 'px';
}
// Save on drag end
api.bus.on('plugin:dragend', ({ el }) => {
if (el.dataset.pluginId === meta.id) {
api.storage.setForPlugin(meta.id, 'pos', {
left: parseInt(el.style.left),
top: parseInt(el.style.top)
});
}
});
}
Saving Lists
export function setup(api) {
let items = api.storage.getForPlugin(meta.id, 'items') || [];
function addItem(text) {
items.push({ text, done: false, id: Date.now() });
api.storage.setForPlugin(meta.id, 'items', items);
}
function removeItem(id) {
items = items.filter(i => i.id !== id);
api.storage.setForPlugin(meta.id, 'items', items);
}
}
Saving Settings with Defaults
const settings = {
is24h: api.storage.getForPlugin(meta.id, '24h') ?? false,
showSeconds: api.storage.getForPlugin(meta.id, 'seconds') ?? true,
theme: api.storage.getForPlugin(meta.id, 'theme') ?? 'dark'
};
// Update and save
function toggle24h() {
settings.is24h = !settings.is24h;
api.storage.setForPlugin(meta.id, '24h', settings.is24h);
}
Reacting to Storage Changes
// Listen for ANY storage change
api.bus.on('storage:change', ({ key, value, oldValue, pluginId }) => {
console.log(`${key}: ${oldValue} → ${value}`);
});
// Listen for changes to your own plugin's storage
api.bus.on('storage:change', ({ key, value }) => {
if (key === `plugin:${meta.id}:theme`) {
applyTheme(value);
}
});
Key Naming
When using plugin-scoped storage, you don’t need to prefix manually:
// ✅ Good — automatic scoping
api.storage.setForPlugin(meta.id, 'theme', 'dark');
api.storage.setForPlugin(meta.id, 'items', [1, 2, 3]);
// ⚠️ Manual prefixing (still works)
api.storage.set(`${meta.id}-theme`, 'dark');
api.storage.set('sticky-notes-list', notes);
The core registry uses board-plugins-registry — avoid that key.
Manual Prefix Keys (Legacy)
If you prefer manual prefixing (the older pattern), it still works:
// ✅ Good
api.storage.set('sticky-notes-list', notes);
api.storage.set('clock-24h', true);
// ❌ Bad — will collide
api.storage.set('data', notes);
api.storage.set('settings', { ... });
Storage Limits
localStorage has a ~5MB limit per origin. For larger data, consider:
- Compressing before storing
- Using IndexedDB
- Storing only what’s needed