Service Worker Lifecycle

The MV3 background is event-driven: it wakes on an event, does its work, then is terminated when idle. Fire events and watch it wake and sleep — and see why globals don't survive.

1 · The worker's life

terminated
Status: terminated (asleep)
Idle shutdown timer:
In-memory counter (a global): lost

2 · Event log

3 · Why globals die — persist instead

Each wake is a fresh start. A counter held in a variable resets; one held in storage survives.

✗ In-memory global

let count = 0;
chrome.action.onClicked
  .addListener(() => {
    count++;            // resets to 0
    console.log(count); //  every wake
  });
Worker terminated → count is gone.

✓ chrome.storage

chrome.action.onClicked
  .addListener(async () => {
    const { c = 0 } =
      await chrome.storage
        .local.get("c");
    await chrome.storage
      .local.set({ c: c + 1 });
  });
Survives termination — single source of truth.