DEV Community

Weather Clock Dash
Weather Clock Dash

Posted on

Using browser.storage.sync vs storage.local in Firefox Extensions: When to Use Each

Using browser.storage.sync vs storage.local in Firefox Extensions: When to Use Each

Firefox extensions have two main storage options: browser.storage.sync and browser.storage.local. Picking the wrong one leads to frustrating UX. Here's how to think about it.

The Core Difference

storage.sync storage.local
Synced across devices Yes (via Firefox Sync) No
Quota 100KB (8KB per item) 10MB
Requires Firefox Sync Yes, to actually sync No
Falls back gracefully Yes (local if not synced) N/A

storage.sync: User Preferences

Use sync for anything that should feel the same across all the user's Firefox installations:

// Settings that should follow the user
await browser.storage.sync.set({
  temperatureUnit: 'celsius',   // °C or °F
  timeFormat: '24h',            // 12h or 24h
  theme: 'dark',                // dark or light
  defaultLocation: 'London',   // weather location
  worldClocks: [               // configured clocks
    { timezone: 'America/New_York', label: 'New York' },
    { timezone: 'Asia/Tokyo', label: 'Tokyo' },
  ]
});
Enter fullscreen mode Exit fullscreen mode

If a user sets their preferred city on their laptop, it should appear on their desktop too.

storage.local: Cached Data

Use local for ephemeral data — API responses, cache, large blobs:

// Cache fetched weather data (don't sync — it's ephemeral)
await browser.storage.local.set({
  weatherCache: {
    London: {
      data: { temp: 15, description: 'Cloudy' },
      timestamp: Date.now()
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

Caching weather data in sync would hit quota limits fast and waste sync bandwidth on data that expires in 10 minutes.

Quota Handling

storage.sync has strict limits:

  • Total: ~100KB
  • Per item: 8KB
  • Number of items: 512

Always handle quota errors gracefully:

async function saveUserPreferences(prefs) {
  try {
    await browser.storage.sync.set(prefs);
  } catch (error) {
    if (error.message.includes('QUOTA_BYTES')) {
      console.warn('Sync storage quota exceeded, falling back to local');
      await browser.storage.local.set(prefs);
    } else {
      throw error;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Reading with Defaults

Always provide defaults when reading — the storage might be empty on first install:

const DEFAULTS = {
  temperatureUnit: 'celsius',
  timeFormat: '24h',
  theme: 'auto',
  defaultLocation: '',
  worldClocks: [],
};

async function loadPreferences() {
  const stored = await browser.storage.sync.get(DEFAULTS);
  // stored will contain stored values OR defaults for missing keys
  return stored;
}
Enter fullscreen mode Exit fullscreen mode

Listening for Cross-Device Changes

When sync is active, settings can change from another device:

browser.storage.onChanged.addListener((changes, area) => {
  if (area !== 'sync') return;

  if (changes.theme) {
    applyTheme(changes.theme.newValue);
  }
  if (changes.temperatureUnit) {
    refreshWeatherDisplay();
  }
  if (changes.worldClocks) {
    rebuildClockList(changes.worldClocks.newValue);
  }
});
Enter fullscreen mode Exit fullscreen mode

This is what makes sync powerful — changes propagate to all open tabs/windows automatically.

The Pattern I Use

In Weather & Clock Dashboard, the storage strategy is:

const SYNC_KEYS = ['theme', 'temperatureUnit', 'timeFormat', 'defaultLocation', 'worldClocks'];
const LOCAL_KEYS = ['weatherCache', 'lastUpdated'];

// On startup: load sync prefs, use local cache
async function init() {
  const prefs = await browser.storage.sync.get(DEFAULTS);
  applyPreferences(prefs);

  // Try to load cached weather first (instant)
  const { weatherCache } = await browser.storage.local.get('weatherCache');
  if (weatherCache && isFresh(weatherCache)) {
    displayWeather(weatherCache.data);
  }

  // Then refresh in background
  fetchAndCacheWeather(prefs.defaultLocation);
}
Enter fullscreen mode Exit fullscreen mode

This gives instant load from cache, with the user's synced location preference, and fresh data arriving silently.

Common Mistakes

  1. Caching API responses in storage.sync — Wastes quota and sync bandwidth
  2. Not providing defaults — Silent failures on first install
  3. Not listening for storage.onChanged — UI won't update when sync kicks in
  4. Storing large blobs in sync — Base64 images, etc. will exceed the 8KB per-item limit

When Firefox Sync is Disabled

storage.sync falls back gracefully — it still works, just locally. You don't need to check whether Firefox Sync is enabled. The extension works the same on a single device; it just won't sync.


Weather & Clock Dashboard — free Firefox new tab extension with live weather, world clocks, search bar. No tracking, MIT licensed.

Top comments (0)