Should You Move Work Off the Main Thread With Web Workers?
Should You Move Work Off the Main Thread?
Sometimes, and less often than the advice suggests. The browser gives a tab one main thread that runs your JavaScript and paints the page. Moving heavy work to a web worker frees that thread. But most slow marketing sites are slow because they run too much code, not because they run it in the wrong place.
We get asked about web workers on almost every performance rescue we take on. A team has read that workers fix responsiveness, and they want to know if that is the missing piece. Usually it is not, and the honest answer saves them a fortnight.
Here is how we decide, and what the browser vendors actually say about it.
What Is the Main Thread and Why Does It Matter?
The main thread is where your page thinks and draws. Google's guidance on off main thread architecture puts it plainly: the browser has just one thread per browser tab, with some exceptions, and it handles both rendering and JavaScript execution. Everything queues behind everything else.
When a long piece of JavaScript is running, the browser cannot paint. A user taps a button and nothing happens, because the thread is busy. That is the whole mechanism behind most of the jank people describe as "the site feels heavy".
Google also makes a point we repeat to clients often: the time it takes to run code on the main thread for a given user is almost completely unpredictable, because device power varies so widely. Your laptop is not the test.
How Much Main Thread Time Is Too Much?
Google draws the line at 50 milliseconds. Any task that takes longer than 50 milliseconds is a long task, and the blocking portion is the task's total time minus that 50 milliseconds. So a 300 millisecond task contributes 250 milliseconds of blocking.
The user facing consequence shows up in Interaction to Next Paint. Google's thresholds are an INP below or at 200 milliseconds for good, above 200 and below or at 500 for needs improvement, and above 500 milliseconds for poor, measured at the 75th percentile and separately for mobile and desktop.
Those two numbers give you a real test. If your field data shows INP above 200 milliseconds and your traces show tasks well over 50 milliseconds, you have a main thread problem worth solving. We cover the measurement side in our piece on Interaction to Next Paint.
What Can Actually Move to a Web Worker?
Computation, and not much else. Web workers can handle state management, parsing, sorting, filtering, compression, image processing, and game logic. What they cannot touch is the DOM. Google's list of what stays on the main thread includes DOM access, WebUSB, WebRTC, Web Audio, and your UI framework's components.
That restriction is the reason most marketing site work does not move. Rendering a nav, animating a hero, running a scroll interaction: all of that is DOM work by definition. A worker cannot help.
Web workers are not new, by the way. They have existed since 2007 and have been supported across all major browsers since 2012. The barrier has never been browser support. It is that the things making your site slow usually are not eligible.
How Do Workers Talk to the Page?
Through message passing, not shared variables. A worker cannot read your page's variables. You send data across with postMessage, and the browser copies it. That copy has a cost, and the cost scales with the size of what you send.
Google gives a usable rule of thumb: you should not break your performance budget if your object's stringified JSON representation is less than 10 KB. Above that, the advice is to move to an ArrayBuffer or WebAssembly, where data can be transferred rather than cloned.
If the message passing overhead is close to the work you are offloading, you have made the page more complicated for nothing. That is the trap. We always measure the copy cost before committing to the pattern.
Is There a Simpler Fix Than a Worker?
Almost always, yes: yield. Instead of moving a long task to another thread, break it into pieces and hand control back to the browser between them. Google's recommended API for this is scheduler.yield(), which is built for yielding to the main thread and gives the continuation of your task priority over other queued work.
The older approach is setTimeout with a delay of zero, which defers code to a separate task. It works, but it has sharp edges. After five rounds of nested setTimeout calls the browser starts imposing a minimum 5 millisecond delay, and your deferred code goes to the back of the queue rather than the front.
Google's batching guidance is to yield about every 50 milliseconds, which lines up neatly with the long task threshold. Worth noting: Google no longer recommends isInputPending, and now advises yielding regardless of whether input is pending.
What About Third Party Scripts?
This is the one place where workers genuinely help a marketing site. Analytics, tag managers and tracking pixels run on your main thread, and you did not write them. Partytown, maintained by QwikDev and currently in Beta, is a lazy loaded library built to relocate resource intensive scripts into a web worker and off the main thread.
It is a real option, and we have used it. It is also fiddly, because third party scripts expect a DOM and Partytown has to proxy that for them. Some scripts work perfectly and some break in ways that are hard to debug, especially anything doing its own cookie or consent work.
Before reaching for it, try removing scripts. We find the fastest win on most sites is deleting two tags nobody can name an owner for, which is the first move in our approach to third party script performance.
What Tooling Makes Workers Bearable?
Raw postMessage is unpleasant to write and worse to maintain. Comlink is the library Google points at, and it lets you use web workers without having to think about the details of postMessage. You call functions across the thread boundary and it handles the plumbing.
Bundler support matters too. Google names worker-plugin for Webpack and rollup-plugin-off-main-thread for Rollup, and notes that Parcel supports workers natively. If your build cannot produce a worker bundle cleanly, the pattern will rot.
For a Webflow site, the practical answer is usually different. You are working within a hosted build, so the realistic levers are removing scripts, deferring them, and using something like Partytown through custom code rather than authoring your own worker.
What Do We Do First on a Slow Site?
We look at field data before we touch anything. If INP is fine and the complaint is about load, workers are irrelevant and the answer lives in payload and render blocking. If INP is poor, we open a trace and find the long tasks.
Then the order is: delete code, defer code, break up code, and only then move code. Deleting is free and always wins. Deferring is cheap. Breaking up with scheduler.yield() is a contained change. Moving to a worker is an architecture decision.
Most sites are fixed in the first two steps, which is why we treat reducing JavaScript bundle size as the default starting point rather than the fallback.
When Is a Worker Genuinely the Right Call?
When the work is real, heavy, and has nothing to do with the DOM. A pricing calculator running a long simulation. A large data table doing client side sorting and filtering over thousands of rows. Image resizing before upload. Parsing a big CSV a user dropped in.
In those cases the worker is not a micro-optimisation. It is the difference between a frozen tab and a page that stays responsive while it thinks. Google frames the benefit as reducing risk rather than pure speed, and we think that is exactly right: the worker protects the experience on the weak devices you cannot test on.
If your site feels heavy and you are not sure whether the cause is the main thread or just too much code, we are happy to look at your field data and tell you which one it is. You can find us at phoenix.studio.
Want a site that performs like this?
Tell us about your project. We will come back with a clear next step, no pressure.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Have a project like this?
Tell us where you want to go. We'll tell you how we'd get you there.