Oxygen runtime
Oxygen is a worker-based runtime for hosting Hydrogen storefronts at the edge.
Worker runtimes are JavaScript-based HTTP servers that are designed for serverless or edge-computing contexts. Workers adapt web browser APIs for server-side applications, so you can use JavaScript-standard Fetch, Streams, URL, Cache-Control, and Web Crypto APIs when you deploy to Oxygen.
Anchor to Runtime mirroringRuntime mirroring
Hydrogen projects include a local development server as a dependency by default. The local development server closely replicates Oxygen's production runtime, so you can be confident that functionality that works in development will also work in production. Both the Oxygen development and production servers are based on Cloudflare's open-source workerd project.
In addition to runtime parity, Hydrogen's bundled development server also returns the same headers sent by Oxygen in production. It also serves static assets, such as images, from a separate localhost domain. This more closely resembles how Shopify's CDN works in production, and can help debug Hydrogen cross-origin resource permission issues earlier in your development process.
To start the development server locally, run the Shopify CLI command shopify hydrogen dev in your Hydrogen project. Consult the Shopify CLI command reference for a complete list of commands and development options.
Hydrogen versions prior to v2024-01 used a Node.js-based development server by default, with lower compatibility. To continue using this version of the development server, pass the --legacy-runtime flag when you run the dev command.
Anchor to Worker compatibility flagsWorker compatibility flags
Since Hydrogen 2024.10.1, on each deploy to Oxygen, Hydrogen uses compatibility date flags.
Hydrogen will update compatibility date flags on every Storefront API release (quarterly).
| Hydrogen version | Compatibility date |
|---|---|
2024.10.1 | 2024-10-01 |
2024.12.1 | 2024-10-01 |
2025.01.1 | 2025-01-01 |
Anchor to Worker runtime APIsWorker runtime APIs
This reference provides a list of the functions that you can use with worker runtime APIs in Oxygen. These APIs are similar to the APIs that are provided by web browsers or Node.js projects.
Anchor to Cache APICache API
Oxygen provides the Cache API that's also supported in major web browsers. The contents of the cache aren't accessible outside of the originating data center.
For developers who are familiar with Cloudflare's Cache API, Oxygen doesn't support the caches.default API.
You can create instances of the Cache object by using the caches.open method:
Anchor to Use HTTPS schemeUse HTTPS scheme
Cache API operations require the Request object to use the HTTPS scheme. Requests with the HTTP scheme will not be cached properly.
- ✅ Good request URL:
https://my-cms.com/api - ❌ Bad request URL:
http://my-cms.com/api
The HTTPS scheme requirement only applies when using the Cache API directly. If you use Hydrogen's built-in cache utilities, then you can use HTTP or HTTPS schemes as you wish.
Anchor to HTTP HeadersHTTP Headers
The cache API supports the following HTTP headers in the HTTP response that's passed to put():
Cache-Control: Refer to the Cloudflare documentation on cache-control directives. For a list of HTTP response codes and their TTL when cache-control directives aren't present, refer to Edge TTL.ETag: Allowscache.match()to evaluate conditional requests that containIf-None-Match.Expires: A string that contains a date in the RFC2616 format, and specifies when the resource becomes invalid. You can use strings that are generated from an instance ofDatebeing passed to the.toUTCSring()method.Last-Modified: Allowscache.match()to evaluate conditional requests withIf-Modified-Since.
Unlike the cache API for Oxygen, the cache API in web browsers ignores HTTP headers on HTTP requests or responses.
HTTP responses that contain Set-Cookie headers aren't cached. To store an HTTP response that contains a Set-Cookie header, you need to use one of the following methods before you use cache.put():
- Delete the HTTP header from the HTTP response.
- Add a
Cache-Control: private=Set-CookieHTTP header in the HTTP response.
Anchor to Cache methodsCache methods
You can use the methods that are described in this section to interact with the cache API in Oxygen.
Anchor to cache.put(request, response)cache. put(request, response)
Adds a response to the cache.
cache.put doesn't support the stale-while-revalidate and stale-if-error directives.
Anchor to cache.put parameterscache. put parameters
request(string orRequestobject): Used as the lookup key to the request. Ifrequestis a string, thenrequestis used as the URL for a newRequestobject.response(Responseobject): AResponseobject that's stored as the value for therequestkey.
Anchor to cache.put returnscache. put returns
Returns a promise that resolves to undefined when the cache stores the response.
Anchor to cache.put errorscache. put errors
cache.put will throw an error if any of the following conditions are met:
- the request passed is a method other than GET.
- the response passed has a status of 206 Partial Content.
cache.put returns a 413 error if any of the following conditions are met:
- the
Cache-Controlvalue is set not to cache. - the
Responseobject is too large.
Anchor to cache.match(request, options)cache. match(request, options)
Checks for a matching response in the cache.
cache.match supports the following HTTP headers in the string or Request object that's passed as the request parameter:
Range: Results in a 206 response if a matching response that contains aContent-LengthHTTP header is found. Your Cloudflare cache respects range requests, even when anAccept-RangesHTTP header is in the response.If-Modified-Since: Results in a 304 response if a matching response contains aLast-ModifiedHTTP header that contains a value that specifies a time after the time that was specified in theIf-Modified-SinceHTTP header.If-None-Match: Results in a 304 response if a matching response contains anETagHTTP header with a value that matches the value that was specified in theIf-None-MatchHTTP header.
cache.match never sends a subrequest to the origin.
cache.match doesn't support the stale-while-revalidate and stale-if-error directives.
Anchor to cache.match parameterscache. match parameters
request(string orRequestobject): Used as the lookup key to the request. Ifrequestis a string, thenrequestis used as the URL for a newRequestobject.options(ignoreMethodoption): WhenignoreMethodevaluates totrue, the request is interpreted as aGETrequest, regardless of the actual value of the request. TheignoreSearchorignoreVaryoptions aren't supported. If you need to use these options, then you can remove query strings or HTTP headers when you usecache.put.
Anchor to cache.match returnscache. match returns
Returns a promise that wraps the Response object that's keyed to the Request object. If a matching response isn't found, then the promise for undefined is returned.
Anchor to cache.match errorscache. match errors
cache.match returns a 504 error when the content is stale.
Anchor to cache.delete(request, options)cache. delete(request, options)
Deletes the Response object from the cache.
Anchor to cache.delete parameterscache. delete parameters
request(string orRequestobject): Used as the lookup key to the request. Ifrequestis a string, thenrequestis used as the URL for a newRequestobject.options: (ignoreMethodoption): WhenignoreMethodevaluates totrue, the request is interpreted as aGETrequest, regardless of the actual value of the request. TheignoreSearchorignoreVaryoptions aren't supported. If you need to use these options, then you can remove query strings or HTTP headers when you usecache.put.
Anchor to cache.delete returnscache. delete returns
Returns a Promise for one of the following Boolean responses:
true: The response was cached, and is now deleted.false: The response wasn't cached at the time of thecache.deletecall.
Anchor to Encoding APIEncoding API
Oxygen supports the following Web APIs:
TextEncoder and TextDecoder only support UTF-8 encoding.
Anchor to Fetch APIFetch API
Oxygen supports the Fetch API, which enables you to fetch resources over the network, and provides generic definitions of the Request, Response, Headers, and other primitives that are used in network requests.
Anchor to fetch methodfetch method
Oxygen supports the top-level fetch method, which is used to fetch resources over the network. The fetch method returns a promise, which is fulfilled when the response is available. Asynchronous fetch calls aren't executed at the top level in a worker script. You can only make calls in the asynchronous request handler method of your worker.
Anchor to HeadersHeaders
Headers is a globally-available constructor that represents HTTP headers in the Fetch API.
The Oxygen implementation of Headers is based on the Headers API.
Anchor to Differences from the standard headers APIDifferences from the standard headers API
- The
Headers.getAllmethod in the standard headers API is deprecated, but you should still use this method with theSet-CookieHTTP header, because cookies often contain date strings, which can be difficult to parse. If you useHeaders.getAllwith other HTTP headers, then an error is thrown. - The
Headers.getmethod returns aUSVStringinstead of aByteString. Unlike aByteString, which represents a sequence of bytes, aUSVStringrepresents a valid sequence of bytes that are convenient to process, and never contain surrogate code points or unpaired surrogate code units.
Anchor to Custom headersCustom headers
Oxygen supports custom HTTP headers that contain meta information about the incoming request. These headers map to Cloudflare's standard fields.
You can access the following HTTP headers on incoming external instances of the Request object:
oxygen-buyer-ip: Customer's IP addressoxygen-buyer-latitude: Customer's geographical latitudeoxygen-buyer-longitude: Customer's geographical longitudeoxygen-buyer-continent: Customer's continentoxygen-buyer-country: Customer's countryoxygen-buyer-region: Customer's regionoxygen-buyer-region-code: Customer's region codeoxygen-buyer-city: Customer's cityoxygen-buyer-timezone: Customer's timezoneoxygen-buyer-postal-code: Customer's postal codeoxygen-buyer-metro-code: Customer's metro code (Designated Market Area)oxygen-buyer-is-eu-country: If the customer's country is in the EU (any non-empty value means yes)
For example, to bind the value of one of the custom HTTP headers to a userCountry constant, you can use the line of code below:
Header values can be undefined if their corresponding information isn't available.
Anchor to Request interfaceRequest interface
The Request interface represents a resource request. All properties of an incoming Request object are read-only.
To modify a request, create a new instance of a Request object and pass the options to the Request object's constructor to modify.
Oxygen supports the following methods on instances of the Request object:
For example, to create an instance of a Response object, you can use the following code:
Anchor to Response(body, init)Response(body, init)
The Response interface represents a response that's sent to the client.
Anchor to Response PropertiesResponse Properties
body(SourceBuffer, FormData, ReadableStream, URLSearchParams, or USVString)init(Optional) (Response object)- The following of
Responseproperties are specific to Oxygen:encodeBody: Workers need to compress data according to thecontent-encodingHTTP header when transmitting data across the network. To serve data that's already compressed, setencodeBodytomanual. By default,encodeBodyis set toauto.
- The following of
Anchor to Response returnsResponse returns
An instance of a Response object.
Anchor to Response methodsResponse methods
You can use the following methods on instances of Response objects.
Anchor to Streams APIsStreams APIs
Oxygen provides APIs for accessing and processing streams of data, which are a subset of the Streams API.
Workers don't need to prepare a complete response body before they return an instance of a Response object. You can use the TransformStream interface to stream a response body after sending the HTTP status and line headers. When response bodies are larger than the memory limit of workers, you'll need to stream data.
To maintain the streaming behavior, only modify the response body by using the methods in the Streams APIs.
If your worker only forwards subrequest responses to the client without reading their body text, then the body handling is already optimized, and you won't benefit from using the Streams API.
For a basic stream usage example, refer to the following code:
Anchor to ReadableStreamReadable Stream
The readable property in TransformStream returns a ReadableStream. You can also construct a new ReadableStream by using the new keyword.
The implementation of ReadableStream that's provided by Oxygen supports the following methods:
Anchor to pipeTo(destination, options)pipe To(destination, options)
Pipes the readable stream to a given writable stream destination and returns a promise that's fulfilled when the write operation succeeds. If the operation fails, then the instance of a promise is rejected.
pipeTo parameters
destination: Refer to the Cloudflare documentation ondestination.optionsRefer to the Cloudflare documentation ondestination. The Oxygen implementation ofoptionssupports the following properties:preventClose: Whentrue, closure of the source,ReadableStream, won't cause the destination,WritableStream, to be closed.preventAbort: Whentrue, errors in the source,ReadableStream, won't abort the destination,WritableStream.
pipeTo returns
A promise that resolves when the piping process has completed, or rejects with the error from the source or any error that occurred while aborting the destination.
Anchor to getReader(options)get Reader(options)
Gets an instance of ReadableStreamDefaultReader and locks the ReadableStream to that reader instance.
For an example of how to create a ReadableStreamBYOBReader, refer to the following code:
getReader parameters
options(key-value pair, wheremodeis the key): An object that specifies options. The only option that's supported ismode, which you can set to'byob'. the'byob'mode creates aReadableStreamBYOBReader.
getReader returns
A ReadableStreamDefaultReader or ReadableStreamBYOBReader object instance, depending on the mode value.
A ReadableStreamBYOBReader enables you to read into a buffer that's provided by a developer. BYOB stands for "bring your own buffer", minimizing the amount of data that's copied in-memory.
An instance of ReadableStreamBYOBReader is similar to the ReadableStreamDefaultReader with the exception of the read method.
You can create an instance of a ReadableStreamBYOBReader by retrieving it from a ReadableStream.
For an example of how to retrieve a ReadableStreamBYOBReader, refer to the following code:
Anchor to MethodsMethods
read(buffer): Returns a promise with the next available chunk of data read into a passed-in buffer. The promise doesn't resolve until at leastminByteshave been read.read: Similar toread(buffer), without a minimum number of bytes that should be read into the buffer. For example, if you allocate 1 MB buffer, then the kernel can fulfill the read with a single byte, whether an EOF follows or not.readusually fills only 1% of the provided buffer.readAtLeast(minBytes, buffer): A non-standard extension to the streams API, which enables users to specify theminBytesneeds to be read into the buffer before resolving the read.
Anchor to ReturnsReturns
Returns a promise with the next available chunk of data that was read into a passed-in buffer.
A ReadableStreamDefaultReader
is used when you want to read from a ReadableStream, rather than piping its output to a WritableStream.
A ReadableStreamDefaultReader is retrieved from a ReadableStream, rather than being created through its constructor.
For an example of how to retrieve a ReadableStreamDefaultReader, refer to the following code:
Anchor to TransformStreamTransform Stream
A TransformStream consists of a writable stream and a readable stream. When data is written to the writable stream, the data is available to be read from the readable stream.
Oxygen provides an identity transform stream, which forwards all chunks that were written to the writable stream to the readable stream without changing the chunks.
Anchor to WritableStreamWritable Stream
A WritableStream is the writable property of a TransformStream. A WritableStream in Oxygen can't be created by using the WritableStream constructor.
You'll want to write to a WritableStream by piping a ReadableStream to it.
For an example of how to pipe a ReadableStream to a WritableStream, refer to the following code:
To write to a WritableStream directly, you need to use its writer:
Refer to the WritableStreamDefaultWriter documentation for more details.
Use a WritableStreamDefaultWriter
when you want to write directly to a WritableStream, rather than piping data to it from a ReadableStream.
For an example of how to write directly to a WritableStream, refer to the code below:
CHANGEME
Anchor to Web Crypto APIWeb Crypto API
The Web Crypto API provides low-level functions for common cryptographic tasks. Oxygen fully implements the Web Crypto API, with the exception of differences in the supported algorithms compared to the algorithms used in most browsers.
The Web Crypto API provides significant speed and security benefits compared to JavaScript implementations.
The Oxygen Web Crypto API is implemented through the SubtleCrypto
interface, accessible through the global crypto.subtle binding. The Oxygen Web Crypto API implementations works differently from the Crypto API in Node.js. Code that uses the Node.js implementation of the Web Crypto API must be changed to work with the implementation provided by Oxygen.
For common uses of the Web Crypto API, refer to the Cloudflare documentation on signing requests.
For a detailed list of supported cryptographic algorithms, refer to the Cloudflare documentation on supported algorithms.
Anchor to JavaScript objects and web APIsJava Script objects and web APIs
Oxygen runs on the V8 JavaScript engine from Google Chrome. The runtime is frequently updated to match the latest stable release of Google Chrome. This enables you to use the latest JavaScript features without needing to transpile your code.
Anchor to Available JavaScript objectsAvailable Java Script objects
All of the standard built-in JavaScript objects are supported, except for the following APIs, for security reasons:
eval()new Function()
The Date.now() method, and any time-related APIs, doesn't provide access to the exact timestamp. Instead, the current time is frozen and points to the timestamp of the last performed I/O operation.
Anchor to Available web APIsAvailable web APIs
The following APIs are globally available:
Anchor to Base64Base64
Anchor to TimersTimers
The following timers are only available inside of the worker's request handler, and can't be used in the global context: