DEV Community

Cover image for Local vs Sync vs Session: Which Chrome Extension Storage Should You Use?
Himanshu
Himanshu

Posted on

Local vs Sync vs Session: Which Chrome Extension Storage Should You Use?

Let's talk about storing data in browser extensions.

We have three options local storage, sync storage and session storage. Each one does something different, and picking the wrong one can lead to headaches down the road…

One quick thing, i created a complete chrome extension boilerplate that lets you ship & monetize your extension fast (includes auth, payments, and everything you need). It’s called extFast

Β 

Overview: Three Types of Extension Storage

Browser extensions have three primary storage APIs, each designed for specific use cases:

  • Local Storage (chrome.storage.local): Stores data locally on the user's device
  • Sync Storage (chrome.storage.sync): Syncs data across devices when the user is signed in
  • Session Storage (chrome.storage.session): Temporary storage that persists only during the browser session

Also these are different from the web's localStorage and sessionStorage APIs. Extension storage APIs work across all extension contexts (background scripts, content scripts, popups).

Β 

Chrome Storage Local: Device-Specific Storage

What is chrome.storage.local?

chrome.storage.local stores data locally on the user's machine. This data persists until explicitly deleted or the extension is uninstalled. It's ideal for storing large amounts of data that don't need to sync across devices.

Key Characteristics

  • Storage Limit: 10 MB (Chrome allows unlimited with unlimitedStorage permission)
  • Persistence: Survives browser restarts
  • Sync: Does NOT sync across devices
  • Browser Support: Chrome MV2 & MV3, Firefox MV2 & MV3
  • Best For: Cached data, large datasets, device-specific settings

Usage Example (Async/Await - Modern)

// Storing data
async function saveToLocal() {
  try {
    await chrome.storage.local.set({
      userPreferences: { theme: 'dark', fontSize: 16 },
      cachedData: [1, 2, 3, 4, 5]
    });
    console.log('Data saved to local storage');
  } catch (error) {
    console.error('Error saving to local storage:', error);
  }
}

// Retrieving data
async function getFromLocal() {
  try {
    const result = await chrome.storage.local.get(['userPreferences', 'cachedData']);
    console.log('User preferences:', result.userPreferences);
    console.log('Cached data:', result.cachedData);
    return result;
  } catch (error) {
    console.error('Error getting from local storage:', error);
  }
}

// Removing data
async function removeFromLocal() {
  try {
    await chrome.storage.local.remove(['cachedData']);
    console.log('Cached data removed');
  } catch (error) {
    console.error('Error removing from local storage:', error);
  }
}

// Clearing all data
async function clearLocal() {
  try {
    await chrome.storage.local.clear();
    console.log('All local storage cleared');
  } catch (error) {
    console.error('Error clearing local storage:', error);
  }
}

Enter fullscreen mode Exit fullscreen mode

Usage Example (Promise-Based - Legacy)

// Storing data
function saveToLocal() {
  chrome.storage.local.set({
    userPreferences: { theme: 'dark', fontSize: 16 },
    cachedData: [1, 2, 3, 4, 5]
  })
  .then(() => {
    console.log('Data saved to local storage');
  })
  .catch((error) => {
    console.error('Error saving to local storage:', error);
  });
}

// Retrieving data
function getFromLocal() {
  chrome.storage.local.get(['userPreferences', 'cachedData'])
    .then((result) => {
      console.log('User preferences:', result.userPreferences);
      console.log('Cached data:', result.cachedData);
    })
    .catch((error) => {
      console.error('Error getting from local storage:', error);
    });
}

// Removing data
function removeFromLocal() {
  chrome.storage.local.remove(['cachedData'])
    .then(() => {
      console.log('Cached data removed');
    })
    .catch((error) => {
      console.error('Error removing from local storage:', error);
    });
}

Enter fullscreen mode Exit fullscreen mode

Chrome Storage Sync: Cross-Device Synchronization

What is chrome.storage.sync?

chrome.storage.sync automatically syncs data across all devices where the user is signed into their browser account. This makes it perfect for user preferences and settings that should follow the user everywhere.

Key Characteristics

  • Storage Limit: 100 KB total, 8 KB per item
  • Persistence: Syncs across signed-in devices
  • Sync Frequency: Automatic when online
  • Browser Support: Chrome MV2 & MV3, Firefox MV2 & MV3
  • Best For: User settings, preferences, small configuration data

Usage Example (Async/Await - Modern)

// Storing data
async function saveToSync() {
  try {
    await chrome.storage.sync.set({
      theme: 'dark',
      language: 'en',
      notifications: true
    });
    console.log('Settings synced across devices');
  } catch (error) {
    console.error('Error saving to sync storage:', error);
  }
}

// Retrieving data
async function getFromSync() {
  try {
    const result = await chrome.storage.sync.get(['theme', 'language', 'notifications']);
    console.log('Theme:', result.theme);
    console.log('Language:', result.language);
    console.log('Notifications:', result.notifications);
    return result;
  } catch (error) {
    console.error('Error getting from sync storage:', error);
  }
}

Enter fullscreen mode Exit fullscreen mode

Usage Example (Promise-Based - Legacy)

// Storing data
function saveToSync() {
  chrome.storage.sync.set({
    theme: 'dark',
    language: 'en',
    notifications: true
  })
  .then(() => {
    console.log('Settings synced across devices');
  })
  .catch((error) => {
    console.error('Error saving to sync storage:', error);
  });
}

// Retrieving data
function getFromSync() {
  chrome.storage.sync.get(['theme', 'language', 'notifications'])
    .then((result) => {
      console.log('Theme:', result.theme);
      console.log('Language:', result.language);
      console.log('Notifications:', result.notifications);
    })
    .catch((error) => {
      console.error('Error getting from sync storage:', error);
    });
}

Enter fullscreen mode Exit fullscreen mode

Chrome Storage Session: Temporary Session Data

What is chrome.storage.session?

chrome.storage.session stores data in memory for the duration of the browser session. Data is cleared when the browser or extension is closed, making it perfect for temporary runtime state.

Key Characteristics

  • Storage Limit: 10 MB
  • Persistence: Only during browser session (cleared on browser close)
  • Browser Support:
    • Chrome: Manifest V3 (Chrome 102+)
    • Firefox: Both Manifest V2 and V3 supported
  • Access Control: By default, not exposed to content scripts (can be changed with setAccessLevel())
  • Best For: Temporary state, session-specific data, runtime variables

Usage Example (Async/Await - Modern)

// Storing session data
async function saveToSession() {
  try {
    await chrome.storage.session.set({
      currentTab: 'dashboard',
      isProcessing: false,
      temporaryToken: 'abc123xyz'
    });
    console.log('Session data stored');
  } catch (error) {
    console.error('Error saving to session storage:', error);
  }
}

// Retrieving session data
async function getFromSession() {
  try {
    const result = await chrome.storage.session.get(['currentTab', 'isProcessing']);
    console.log('Current tab:', result.currentTab);
    console.log('Is processing:', result.isProcessing);
    return result;
  } catch (error) {
    console.error('Error getting from session storage:', error);
  }
}

// Updating session data
async function updateSessionState() {
  try {
    await chrome.storage.session.set({ isProcessing: true });
    // Do some work...
    await chrome.storage.session.set({ isProcessing: false });
  } catch (error) {
    console.error('Error updating session storage:', error);
  }
}

// Setting access level (allows content scripts to access), call this function from background script (for example on extension installed)
async function enableContentScriptAccess() {
  try {
    await chrome.storage.session.setAccessLevel({
      accessLevel: 'TRUSTED_AND_UNTRUSTED_CONTEXTS'
    });
    console.log('Content scripts can now access session storage');
  } catch (error) {
    console.error('Error setting access level:', error);
  }
}

Enter fullscreen mode Exit fullscreen mode

Usage Example (Promise-Based - Legacy)

// Storing session data
function saveToSession() {
  chrome.storage.session.set({
    currentTab: 'dashboard',
    isProcessing: false,
    temporaryToken: 'abc123xyz'
  })
  .then(() => {
    console.log('Session data stored');
  })
  .catch((error) => {
    console.error('Error saving to session storage:', error);
  });
}

// Retrieving session data
function getFromSession() {
  chrome.storage.session.get(['currentTab', 'isProcessing'])
    .then((result) => {
      console.log('Current tab:', result.currentTab);
      console.log('Is processing:', result.isProcessing);
    })
    .catch((error) => {
      console.error('Error getting from session storage:', error);
    });
}

Enter fullscreen mode Exit fullscreen mode

Storage Comparison Table

Feature Local Storage Sync Storage Session Storage
Storage Limit 10 MB (unlimited with permission) 100 KB 10 MB
Syncs Across Devices No Yes No
Persistence Until deleted Until deleted Session only
Chrome Support MV2 & MV3 MV2 & MV3 MV3
Firefox Support MV2 & MV3 MV2 & MV3 MV2 & MV3
Best Use Case Large data, cache User preferences Temporary state
Speed Fast Slower (sync overhead) Fast (in-memory)

Chrome vs Firefox: Key Differences

Browser Namespace Compatibility

Both Chrome and Firefox support similar storage APIs, but Firefox uses a different namespace:

// Chrome (and Chromium-based browsers)
chrome.storage.local.set({ key: 'value' });

// Firefox supports both namespaces
browser.storage.local.set({ key: 'value' }); // Preferred in Firefox
chrome.storage.local.set({ key: 'value' });   // Also works in Firefox

// Cross-browser compatible approach
const storageAPI = typeof browser !== 'undefined' ? browser : chrome;
await storageAPI.storage.local.set({ key: 'value' });

Enter fullscreen mode Exit fullscreen mode

Manifest Configuration Examples

Firefox Manifest V2:

{
  "manifest_version": 2,
  "name": "My Extension",
  "version": "1.0",
  "permissions": ["storage"], πŸ‘ˆ
  "background": {
    "scripts": ["background.js"],
    "persistent": true
  }
}

Enter fullscreen mode Exit fullscreen mode

Chrome Manifest V3:

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "permissions": ["storage"], πŸ‘ˆ
  "background": {
    "service_worker": "background.js"
  }
}

Enter fullscreen mode Exit fullscreen mode

Firefox Manifest V3:

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "permissions": ["storage"], πŸ‘ˆ
  "background": {
    "scripts": ["background.js"]
  }
}

Enter fullscreen mode Exit fullscreen mode

source

Listening to Storage Changes

Monitor storage changes across all extension contexts:

Async/Await Example

// Listen to all storage areas
chrome.storage.onChanged.addListener((changes, areaName) => {
  console.log(`Storage area '${areaName}' changed`);

  for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
    console.log(`Key '${key}' changed from`, oldValue, 'to', newValue);
  }
});

// Listen to specific storage area
chrome.storage.session.onChanged.addListener((changes) => {
  if (changes.isProcessing) {
    console.log('Processing state changed:', changes.isProcessing.newValue);
  }
});

// Firefox-specific listener using browser namespace
if (typeof browser !== 'undefined') {
  browser.storage.session.onChanged.addListener((changes) => {
    console.log('Session storage changed (Firefox):', changes);
  });
}

Enter fullscreen mode Exit fullscreen mode

2. Handle Storage Quota

async function checkStorageQuota() {
  try {
    // Check local storage quota
    const localBytes = await chrome.storage.local.getBytesInUse();
    console.log(`Local storage using ${localBytes} bytes`);

    // Check session storage quota
    if (chrome.storage.session) {
      const sessionBytes = await chrome.storage.session.getBytesInUse();
      console.log(`Session storage using ${sessionBytes} bytes`);
    }
  } catch (error) {
    console.error('Error checking quota:', error);
  }
}

Enter fullscreen mode Exit fullscreen mode

yeah pretty much done now!

Β 
PS: if you want to build & monetize your extension fast, you can checkout my chrome extension boilerplate: extFast

thankyou soo much for reading πŸ’›

bye bye :)

Top comments (0)