PageSpeed Fix · June 2026

Minimize Main-Thread Work on Shopify: Fix the PageSpeed Warning (2026)

To minimize main-thread work on Shopify, reduce JavaScript execution, defer app scripts, break long tasks, simplify layout work, and remove unused theme code. Start with a free Shopify speed test; Thunder handles the highest-impact script deferral automatically before you touch code.

~12 min read · JavaScript examples included

Quick Fix with Thunder

On Shopify, main-thread work is rarely one clean file you can edit. It is usually your theme plus a stack of review widgets, popups, analytics tools, subscriptions, chat, upsells, and page builder scripts. Thunder improves the loading order and defers non-critical JavaScript so the browser can render content and respond to users sooner.

If PageSpeed also reports render-blocking resources, read our render-blocking resources guide. If the field metric is red, use our Shopify INP guide after applying Thunder.

Install Thunder

What the Main Thread Actually Does

The browser’s main thread is the single lane where most visible page work happens. It parses HTML, parses CSS, calculates which styles apply, computes layout, paints pixels, handles input, and runs JavaScript. When JavaScript is running, the browser cannot simultaneously respond to a tap, update layout, or paint a new frame.

Lighthouse breaks this down into categories such as script evaluation, script parsing and compilation, style and layout, rendering, parse HTML and CSS, and garbage collection. Shopify merchants often see script evaluation dominate the report because app scripts run on every page even when the customer never opens the widget.

This is why the warning matters beyond the lab score. High main-thread work inflates Total Blocking Time, and Total Blocking Time is a strong lab signal for real interaction pain. Google’s INP threshold for a good experience is under 200ms; if the main thread is busy, the click waits.

Why Shopify Stores Trigger This Warning

App JavaScript

Reviews, chat, popups, analytics, loyalty, subscriptions, and bundles all execute code on the same thread.

Theme features

Sliders, predictive search, quick view, variant pickers, animations, and mega menus add event handlers and layout work.

Large DOM

Thousands of nodes make style calculation and layout more expensive. See our DOM size guide.

Step 1: Find the Long Tasks

Open Chrome DevTools, go to Performance, record a page load, and look for long yellow tasks. Any task over 50ms blocks the main thread long enough to count toward Total Blocking Time.

// Quick field debugging in the browser console
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('Long task:', Math.round(entry.duration), 'ms');
  }
}).observe({ type: 'longtask', buffered: true });

If the worst tasks come from third-party domains, use our third-party scripts guide. If they come from your own theme bundle, continue below.

Step 2: Defer Non-Critical Theme Scripts

Scripts in the head without deferral block parsing and compete for the main thread early. For theme scripts that do not need to run before content appears, use defer:

<script src="{{ 'theme.js' | asset_url }}" defer></script>

Be careful with dependencies. If a variant picker depends on a global library loaded before it, preserve order. Do not blindly add async to everything; async can execute files out of order. Thunder handles dependency-aware deferral for app scripts, which is usually where the biggest gain lives.

Step 3: Load Widgets Only When Needed

Chat, review carousels, recommendation blocks, and video embeds often do not need to initialize at page load. Load them when visible or after interaction.

const widget = document.querySelector('[data-reviews-widget]');

const observer = new IntersectionObserver((entries) => {
  if (!entries.some((entry) => entry.isIntersecting)) return;

  import('./reviews-widget.js').then((module) => {
    module.init(widget);
  });

  observer.disconnect();
}, { rootMargin: '300px' });

if (widget) observer.observe(widget);

This pattern keeps unused JavaScript off the critical path. For images and embeds, pair it with our Shopify lazy loading guide.

Step 4: Break Up Long JavaScript Tasks

If your theme loops through hundreds of DOM nodes, recalculates prices, updates filters, or renders search results in one big block, yield back to the browser between chunks.

async function renderProducts(products) {
  for (let i = 0; i < products.length; i += 12) {
    renderProductBatch(products.slice(i, i + 12));

    if ('scheduler' in window && 'yield' in scheduler) {
      await scheduler.yield();
    } else {
      await new Promise((resolve) => setTimeout(resolve, 0));
    }
  }
}

This does not reduce total work, but it prevents one long task from blocking input. That helps INP, especially on mobile where CPU throttling makes every millisecond of script work more expensive. For deeper JavaScript cleanup, use our Shopify JavaScript optimization guide.

Step 5: Avoid Layout Thrashing

Layout thrashing happens when code repeatedly reads layout values and writes DOM changes in the same loop. Each read can force the browser to recalculate layout synchronously.

// Bad: read and write in the same loop
cards.forEach((card) => {
  const height = card.offsetHeight;
  card.style.minHeight = height + 20 + 'px';
});

// Better: batch reads, then batch writes
const heights = cards.map((card) => card.offsetHeight);
cards.forEach((card, index) => {
  card.style.minHeight = heights[index] + 20 + 'px';
});

This matters on collection pages, quick-add drawers, sticky headers, and product media galleries. If PageSpeed shows both main-thread work and high style/layout cost, inspect these interactive components first.

Manual Fix vs Thunder Fix

Main-thread issueManual fixThunder fix
App script executionAudit each app and defer/remove scriptsAutomatically defers non-critical app scripts
Render-blocking theme JSAdd defer and test dependenciesOptimizes loading order around critical content
Long custom tasksRewrite JS to chunk work and yieldReduces competing script load; custom code still needs cleanup
High style/layout workReduce DOM and layout thrashingKeeps scripts from piling onto the layout bottleneck

Retest the Right Metrics

After changes, retest mobile first. Watch Total Blocking Time in Lighthouse, INP in field data, and the main-thread category breakdown. Do not chase a perfect score on one synthetic run; compare several runs and use Shopify’s Web Performance dashboard for real-user trends.

If your LCP is also high, the next bottleneck may be your hero image. Use our Shopify hero image preload guide and the broader Shopify speed optimization guide. If PageSpeed also reports high Shopify Total Blocking Time, critical request chains, enormous network payloads, or non-composited animations, fix those diagnostics in the same audit pass. For pricing and automation options, see Thunder pricing.

References and Validation

Use Lighthouse's main-thread work breakdown as the source of truth for what the diagnostic measures. It separates script evaluation, parsing, style and layout, rendering, and other browser work so you can tell whether the issue is your theme code, your app stack, or the amount of DOM the browser has to process.

For responsiveness, cross-check with web.dev's INP guidance. A store can look visually loaded while still feeling broken if the main thread is busy when the customer taps a variant, opens the cart drawer, or clicks checkout. That is why Thunder focuses so heavily on third-party script deferral: it gives the browser room to respond before the visitor loses patience.

Do It Yourself

Free plan · 1-click install · Instant results

Install Thunder Free →

Done For You

Core Web Vitals guarantee · 2-week delivery · 6 months Thunder free

Get Expert Optimization →

Starting from €1,500

FAQ

What is main-thread work in PageSpeed Insights?

Main-thread work is the browser time spent parsing HTML and CSS, calculating styles, laying out the page, rendering pixels, compiling JavaScript, and executing JavaScript. When this work takes too long, the page loads slowly and responds late to taps or clicks.

Why do Shopify stores have high main-thread work?

The biggest cause is JavaScript from apps, analytics, chat widgets, reviews, popups, page builders, and theme features. Large DOM size, complex CSS, sliders, and quick-add product grids add more style and layout work.

Does minimizing main-thread work improve INP?

Yes. INP measures how quickly the page responds to interactions. If the main thread is busy executing JavaScript or recalculating layout, the browser cannot respond immediately, so INP gets worse.

Can Thunder minimize main-thread work automatically?

Thunder automatically defers non-critical app and theme scripts, reduces render-blocking behavior, and improves loading order. That removes a large share of the main-thread pressure on typical Shopify stores.

What is a long task?

A long task is JavaScript or browser work that occupies the main thread for more than 50 milliseconds. Long tasks block input, delay paints, and increase Total Blocking Time in Lighthouse.

Should I use async or defer on Shopify scripts?

Use defer for scripts that depend on page structure or execution order. Use async only for independent scripts such as simple analytics beacons. For app scripts you do not control, a dependency-aware optimizer like Thunder is safer than blindly editing tags.