Skip to main content

Oxygen runtime

Oxygen runs your storefront as a Web Worker on Cloudflare's open-source workerd runtime. Workers use web-standard APIs, such as fetch, Request, Response, Streams, URL, and Web Crypto, instead of Node APIs. For details about the standard APIs, refer to MDN and Cloudflare's Workers runtime APIs.

This page covers what's specific to Oxygen.


MiniOxygen runs your Worker locally on workerd with sample Oxygen request headers. Test runtime APIs on a preview deployment.

At build time, MiniOxygen sets the Worker's compatibility date from your Hydrogen version by default. Hydrogen 2026-10 uses 2026-10-01. The React Router template sets 2026-04-01. The compatibility date controls which runtime behavior changes apply to your Worker.


Oxygen adds the following headers to each incoming request. A header is missing when Oxygen doesn't have its value.

HeaderValue
oxygen-buyer-ipThe buyer's IP address. Pass it as buyerIp to createShopifyRequestContext().
oxygen-buyer-countryThe buyer's country.
oxygen-buyer-regionThe buyer's region.
oxygen-buyer-region-codeThe buyer's region code.
oxygen-buyer-cityThe buyer's city.
oxygen-buyer-postal-codeThe buyer's postal code.
oxygen-buyer-continentThe buyer's continent.
oxygen-buyer-latitudeThe buyer's latitude.
oxygen-buyer-longitudeThe buyer's longitude.
oxygen-buyer-timezoneThe buyer's time zone.
oxygen-buyer-metro-codeThe buyer's metro code (Designated Market Area).
oxygen-buyer-is-eu-countryAny non-empty value means that the buyer's country is in the EU.

Location headers are approximate. Use them for defaults, such as suggesting a market, but let buyers change the result. For more information, refer to Markets.


Open a cache with caches.open() and pass it to the Storefront API client, as described in Caching. Oxygen doesn't support caches.default, and each data center has its own cache.

If you use the Cache API directly, instead of through the Storefront API client, then note the following:

  • Cache keys must use https: URLs. Requests with http: URLs aren't cached.
  • The cache reads Cache-Control, Expires, ETag, and Last-Modified from the response that you pass to cache.put(). Browser caches ignore these headers, but Oxygen's cache doesn't.
  • Responses with a Set-Cookie header aren't cached. Remove the header, or add Cache-Control: private=Set-Cookie, before you call cache.put().

Anchor to Differences from NodeDifferences from Node

Oxygen doesn't include Node APIs. Replace the following in your server code:

Node APIUse instead
BufferUint8Array, TextEncoder, TextDecoder, atob(), and btoa(). TextEncoder and TextDecoder support only UTF-8.
node:cryptoWeb Crypto, through crypto.subtle. For supported algorithms, refer to Cloudflare's Web Crypto docs.
Node streamsWeb Streams, such as ReadableStream and TransformStream.
fs and other node:* modulesBundle static data into your build, or fetch it.
process.envThe Worker's env argument. Refer to Read variables in your app.

  • Request scope: Call fetch(), setTimeout(), and setInterval() inside the request handler, not at module scope.
  • Dynamic code: eval() and new Function() aren't available.
  • Time: Date.now() returns the time of the last I/O operation, not the exact current time. Don't use it to measure code that doesn't do I/O.
  • Headers: To read multiple Set-Cookie values, use headers.getSetCookie().


Was this page helpful?