---
title: Performance best practices for Hydrogen storefronts
description: >-
  Understand where Hydrogen performance work diverges from Liquid theme
  performance work, which Liquid patterns still apply, and which Hydrogen guide
  to read for each task.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/hydrogen-performance
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/hydrogen-performance.md
api_name: hydrogen
api_type: framework
---

# Performance best practices for Hydrogen storefronts

Most of this section assumes a Liquid theme, where Shopify renders and caches HTML for you and your work is mostly about what the browser does after the HTML arrives. Hydrogen is a React application that you write, build, and run yourself on Oxygen, so you own layers that the platform handles for a Liquid theme: data fetching, response caching, and how much JavaScript ships per route.

This page is the bridge. It maps Liquid theme performance concerns onto their Hydrogen equivalents, then points you at the dedicated [Hydrogen performance guides](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/data-loading) for the implementation details.

***

## Set up analytics first

Configure [analytics event tracking with Hydrogen](https://shopify.dev/docs/storefronts/headless/hydrogen/analytics/tracking?framework=hydrogen\&extension=javascript) before you optimize anything else. A Liquid theme reports [Core Web Vitals](https://web.dev/vitals/) to your Shopify Web Performance Dashboard without any setup. A Hydrogen storefront doesn't, so until tracking is wired up you have no [field data](https://shopify.dev/docs/storefronts/themes/best-practices/performance/lab-vs-field), no regression detection, and no benchmark to compare against.

***

## Hydrogen and Liquid: where performance patterns diverge

| Concern | Liquid theme | Hydrogen storefront |
| - | - | - |
| Server render time | You optimize Liquid rendering: [move work out of loops](https://shopify.dev/docs/storefronts/themes/best-practices/performance/move-operations-outside-loops), [avoid nested renders](https://shopify.dev/docs/storefronts/themes/best-practices/performance/avoid-nested-renders). Shopify runs the queries. | You write the queries. How you fetch data in route loaders dominates TTFB, so parallelize with `Promise.all` and don't over-fetch. See [Performant data loading with Hydrogen](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/data-loading). |
| Diagnosing a slow server response | Theme Inspector Chrome extension shows Liquid render time per section. | The [Subrequest Profiler](https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/subrequest-profiler) shows every request a route makes, in order, so you can spot waterfalls. |
| Response caching | Shopify's CDN caches storefront HTML. There's nothing to configure. | Subrequest caching is yours to choose per query (`CacheShort`, `CacheLong`, `CacheNone`), and full-page caching is opt-in through the `Oxygen-Cache-Control` header. See [Caching](https://shopify.dev/docs/storefronts/headless/hydrogen/caching) and [Oxygen full-page cache](https://shopify.dev/docs/storefronts/headless/hydrogen/caching/full-page-cache). |
| Partial page updates | [Section Rendering API](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-section-rendering-api) returns rendered section HTML. | Route loaders return data, and non-critical data streams in behind `Suspense` and `Await` instead of blocking the response. See [Prioritize critical data](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/data-loading#prioritize-critical-data). |
| JavaScript weight | Scripts are what you add to the theme, so you [defer them](https://shopify.dev/docs/storefronts/themes/best-practices/performance/defer-scripts) or [load them on interaction](https://shopify.dev/docs/storefronts/themes/best-practices/performance/load-javascript-on-user-interaction). | Every dependency a component imports lands in that route's bundle, whether or not the customer interacts with it. Import cost is the lever, so [inspect your bundle size](https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/bundle-size) to find the heaviest dependencies. |
| Time to interactive | Server-rendered HTML is interactive as soon as your own scripts run. | React hydrates the server-rendered HTML before the page responds to input, so a heavy route can paint quickly and still feel unresponsive. This is an [INP](https://shopify.dev/docs/storefronts/themes/best-practices/performance/understanding-inp) problem, not an LCP problem. |
| Startup cost | Not applicable. | Your worker has to boot on Oxygen. Measure it with `npx shopify hydrogen debug cpu`. See [Measure CPU startup time locally](https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/cpu-startup). |
| Images | Liquid image filters plus explicit `width` and `height`. See [Use responsive images](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-responsive-images). | Hydrogen's [`Image`](https://shopify.dev/docs/api/hydrogen-react/latest/components/media/image) component generates `srcset` and `sizes`, and takes an `aspectRatio` prop to hold layout. See [Render responsive images](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/on-page-optimizations#render-responsive-images). |
| Speculative navigation | [Speculation Rules API](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-speculation-rules) in the theme. | Built-in link pre-fetching with `prefetch="intent"` or `prefetch="viewport"`. See [Use pre-fetching](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/on-page-optimizations#use-pre-fetching). |
| Perceived latency on cart actions | Cart updates round-trip to the server. | `useOptimisticCart` and `useOptimisticVariant` update the UI before the server responds. See [Implement optimistic UIs](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/on-page-optimizations#implement-optimistic-uis). |

***

## What carries over unchanged

These are browser-level constraints, so the guidance in this section applies to a Hydrogen storefront as written:

* [Never lazy load the LCP image](https://shopify.dev/docs/storefronts/themes/best-practices/performance/never-lazy-load-lcp-image) and [set `fetchpriority="high"` on it](https://shopify.dev/docs/storefronts/themes/best-practices/performance/set-fetchpriority-high-on-lcp-image).
* [Prevent image layout shift](https://shopify.dev/docs/storefronts/themes/best-practices/performance/prevent-image-layout-shift) by reserving dimensions.
* Font strategy: [self-host web fonts](https://shopify.dev/docs/storefronts/themes/best-practices/performance/self-host-web-fonts) and [reduce CLS from font swapping](https://shopify.dev/docs/storefronts/themes/best-practices/performance/reduce-cls-font-swapping).
* [Render essential content server-side](https://shopify.dev/docs/storefronts/themes/best-practices/performance/render-essential-content-server-side) rather than fetching it from the client after load.
* [Don't hide the LCP image behind animations](https://shopify.dev/docs/storefronts/themes/best-practices/performance/dont-hide-lcp-image-behind-animations), and [use `transform` for animations](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-transform-for-animations).

Third-party scripts are the one case that looks the same and isn't. The main-thread cost is identical, but the delivery mechanism differs: in a Liquid theme a script is a tag you can defer or drop, whereas in Hydrogen a third-party SDK imported by a component becomes part of that route's JavaScript bundle. Auditing a Hydrogen storefront means reading the [bundle size report](https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/bundle-size) as well as the network waterfall. The decision framework in [Audit and remove third-party scripts](https://shopify.dev/docs/storefronts/themes/best-practices/performance/audit-remove-third-party-scripts) still holds.

***

## Testing

Hydrogen-specific tools:

* [Subrequest Profiler](https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/subrequest-profiler) for request waterfalls in loaders.
* [Bundle size analyzer](https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/bundle-size), through `npx shopify hydrogen build` output and the report it generates, for per-dependency JavaScript weight.
* `npx shopify hydrogen debug cpu` for worker startup time.

Browser tools, which work the same way as they do for a Liquid theme:

* Record a page load in the Chrome DevTools **Performance** panel, and look at the work after first paint to see how long hydration takes.
* Use the **Coverage** tab, under **Sources**, to find JavaScript that a route ships but doesn't run.
* Use the **Lighthouse** panel for lab LCP, CLS, and Total Blocking Time, which correlates with INP.

For field data, check your Shopify Web Performance Dashboard after analytics tracking is configured. See [Testing for performance](https://shopify.dev/docs/storefronts/themes/best-practices/performance/testing-for-performance).

***

## References

* [Performant data loading with Hydrogen](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/data-loading)
* [On-page optimizations](https://shopify.dev/docs/storefronts/headless/hydrogen/performance/on-page-optimizations)
* [Hydrogen debugging](https://shopify.dev/docs/storefronts/headless/hydrogen/debugging)
* [Caching in Hydrogen](https://shopify.dev/docs/storefronts/headless/hydrogen/caching)
* [Analytics event tracking with Hydrogen](https://shopify.dev/docs/storefronts/headless/hydrogen/analytics/tracking?framework=hydrogen\&extension=javascript)
* [Hydrogen production checklist](https://shopify.dev/docs/storefronts/headless/hydrogen/production-checklist)

***
