Skip to content

SharedWorker

A SharedWorker is a Web Worker that is shared across all browsing contexts (tabs, windows, iframes) of the same origin. Unlike a Dedicated Worker, which exists only for one page, a SharedWorker lives until all connected tabs close. Think of it as a lightweight in-browser “service” — it can hold shared state, deduplicate network requests, and synchronize data across tabs without a backend.

Dedicated WorkerSharedWorker
Instance per tab?Yes — one per pageNo — one shared across all tabs
Constructornew Worker(url)new SharedWorker(url)
Communicationworker.postMessage directworker.port.postMessage via MessagePort
Worker receives connect?NoYes — onconnect event fires on each new tab
LifetimeTied to the owning pageUntil all connected tabs close

There are four key steps to using a SharedWorker.

Step 1 — In the main thread:

const worker = new SharedWorker('shared-worker.js');
worker.port.start(); // must call start() to activate the port
worker.port.postMessage('hello');
worker.port.onmessage = (e) => console.log(e.data);

Step 2 — In the worker (shared-worker.js):

const ports = [];
self.onconnect = (e) => {
const port = e.ports[0];
ports.push(port);
port.start();
port.onmessage = (ev) => {
// echo to all connected tabs
for (const p of ports) p.postMessage('echo: ' + ev.data);
};
};

The real power of SharedWorker is cross-tab shared state. Opening one tab barely demonstrates it — you need at least two. That is why the runnable below opens in StackBlitz, where you can open two browser panes pointing at the same URL.

Runnable: shared counter across tabs (StackBlitz)

Section titled “Runnable: shared counter across tabs (StackBlitz)”
SharedWorker

Needs multiple tabs / a SharedWorker context — open in StackBlitz to run.

OptionBenefitCost
SharedWorker (one instance for every tab)Saves memory, shares state and coordination across tabs immediately (e.g. one connection for many tabs)Harder to debug — DevTools needs a separate panel for the shared worker, and historically iOS Safari didn’t support it or supported it incompletely
Dedicated Worker (one instance per tab)Supported in every browser, easier to debug since it’s tied to a single pageUses more memory with many tabs open, and has no built-in shared state
  • Relying on SharedWorker in iOS Safari with no fallback — its support on iOS Safari has historically been inconsistent. Feature-detect with typeof SharedWorker !== 'undefined' and fall back to a Dedicated Worker or another mechanism.
  • Forgetting to call port.start() — both the page side and the worker side must call port.start() before messages flow through the MessagePort. Otherwise messages just sit queued and never arrive.
  • Expecting onconnect to fire only once — onconnect fires every time a new tab connects. Push each new port onto your existing list instead of overwriting it, or older tabs get disconnected from communication.
How many SharedWorker instances exist when three tabs on the same origin all call `new SharedWorker('sw.js')`?
Which event fires in the SharedWorker script when a new tab connects?
Why must you call `port.start()` in a SharedWorker?
Which prop do you pass to StorageRunner to open a SharedWorker demo in StackBlitz?