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.
Each wake is a fresh start. A counter held in a variable resets; one held in storage survives.
let count = 0;
chrome.action.onClicked
.addListener(() => {
count++; // resets to 0
console.log(count); // every wake
});
count is gone.chrome.action.onClicked
.addListener(async () => {
const { c = 0 } =
await chrome.storage
.local.get("c");
await chrome.storage
.local.set({ c: c + 1 });
});