---
title: Self-hosting Hydrogen
description: >-
  If you don’t want to deploy to Oxygen, then you can host Hydrogen on other
  providers or runtimes, such as Vercel, Netlify, Fly.io, Cloudflare Workers,
  and more.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/headless/legacy/hydrogen/deployments/self-hosting
  md: >-
    https://shopify.dev/docs/storefronts/headless/legacy/hydrogen/deployments/self-hosting.md
api_name: hydrogen
---

Legacy Hydrogen

These pages refer to Hydrogen versions 2026-04 and earlier. For versions 2026-10 and later, refer to the latest [Hydrogen docs](https://shopify.dev/docs/storefronts/hydrogen). If you're not using the latest version of Hydrogen, then we recommend that you migrate your storefront. To learn more, refer to [Migrate to the latest version of Hydrogen](https://shopify.dev/docs/storefronts/hydrogen/migrate).

# Self-hosting Hydrogen

**Note:**

This guide might not be compatible with features introduced in Hydrogen version 2025-05 and above. Check the [2026-04 reference](https://shopify.dev/docs/api/hydrogen/2026-04) if you encounter any issues.

If you don’t want to [deploy to Oxygen](https://shopify.dev/docs/storefronts/headless/legacy/hydrogen/deployments), then you can host Hydrogen on other JavaScript runtimes, such as Vercel, Netlify, Fly.io, and Cloudflare Workers.

***

## Requirements

* [Install the Headless channel](https://shopify.dev/docs/storefronts/headless/bring-your-own-stack). This gives you access to the Storefront API and Customer Account API. You can also manage API tokens.

***

## Steps to update your Hydrogen app

**Note:**

Your hosting platform might have other requirements or implementation details not covered here.

### Step 1: Choose a React Router deployment target

Hydrogen projects are React Router apps. To self-host a Hydrogen app, configure the project for the runtime or platform that serves your app. Start with React Router's [deployment guide](https://reactrouter.com/start/framework/deploying) and [deployment templates](https://github.com/remix-run/react-router-templates).

For platform-specific setup, refer to your host's React Router guide, such as:

* [Cloudflare Workers](https://developers.cloudflare.com/workers/framework-guides/web-apps/react-router/).
* [Netlify](https://docs.netlify.com/build/frameworks/framework-setup-guides/react-router/).
* [Vercel](https://vercel.com/templates/react-router/react-router-boilerplate).

1. Remove Oxygen-specific packages and code that your new target doesn't use. If your server entry no longer imports `@shopify/remix-oxygen`, then uninstall it:

```sh
npm uninstall @shopify/remix-oxygen
```

1. In `vite.config.ts`, remove the Oxygen Vite plugin from the `plugins` array, such as `oxygen()`, but keep Hydrogen's Vite plugin, `hydrogen()`.
2. Install the packages that your selected host requires, such as a React Router preset, runtime adapter, server package, or environment type package. Follow your host's React Router guide for exact commands and configuration.

### Step 2: Edit app files for your target runtime

When you move from Oxygen to another runtime, update the files that define your server runtime and build target:

* `server.js`, `server.ts`, or another server entry file.
* `react-router.config.ts`.
* `vite.config.ts`.
* `app/entry.server.jsx` or `app/entry.server.tsx` when your runtime needs a custom server entry.

React Router provides [templates](https://github.com/remix-run/react-router-templates) for different deployment targets. Consult your chosen target's template files for specific configuration and build steps. For non-Node.js runtimes, you might also need a custom [`app/entry.server.tsx`](https://reactrouter.com/api/framework-conventions/entry.server.tsx) file.

### Step 3: Keep Hydrogen context in React Router

Hydrogen utilities need the Storefront API client, session, cache, and other runtime services in React Router's load context. When you replace the Oxygen runtime, make sure that your new server entry creates a Hydrogen context and passes it through `getLoadContext`.

The following example shows the Hydrogen-specific part of a Fetch API server entry. It uses `AppSession` as a placeholder for the session implementation that your runtime uses.

## File

## /server.js

##### JavaScript

```js
import {createHydrogenContext, createRequestHandler} from '@shopify/hydrogen';
import * as reactRouterBuild from 'virtual:react-router/server-build';

export default {
  async fetch(request, env, executionContext) {
    const session = await AppSession.init(request, [env.SESSION_SECRET]);
    const hydrogenContext = createHydrogenContext({
      env,
      request,
      cache: await caches.open('hydrogen'),
      waitUntil: executionContext.waitUntil.bind(executionContext),
      session,
    });

    const handleRequest = createRequestHandler({
      build: reactRouterBuild,
      mode: process.env.NODE_ENV,
      getLoadContext: () => hydrogenContext,
    });

    const response = await handleRequest(request);

    if (session.isPending) {
      response.headers.set('Set-Cookie', await session.commit());
    }

    return response;
  },
};
```

##### TypeScript

```ts
import {createHydrogenContext, createRequestHandler} from '@shopify/hydrogen';
import * as reactRouterBuild from 'virtual:react-router/server-build';

export default {
  async fetch(request: Request, env: Env, executionContext: ExecutionContext) {
    const session = await AppSession.init(request, [env.SESSION_SECRET]);
    const hydrogenContext = createHydrogenContext({
      env,
      request,
      cache: await caches.open('hydrogen'),
      waitUntil: executionContext.waitUntil.bind(executionContext),
      session,
    });

    const handleRequest = createRequestHandler({
      build: reactRouterBuild,
      mode: process.env.NODE_ENV,
      getLoadContext: () => hydrogenContext,
    });

    const response = await handleRequest(request);

    if (session.isPending) {
      response.headers.set('Set-Cookie', await session.commit());
    }

    return response;
  },
};
```

The `cache` object should implement the standard [Web Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache). Check with your chosen hosting platform for more details about its caching implementation.

The `waitUntil` method keeps serverless request work running after the handler sends a response. Check whether your hosting platform supports this pattern, or one like it. For example, Vercel Functions provide a compatible [`waitUntil` method](https://vercel.com/docs/functions/functions-api-reference#waituntil). You don't need this method when you deploy to a stateful Node.js server, because the server keeps running after the handler returns a response.

Consult the [`createHydrogenContext` API reference](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/createhydrogencontext) and [`createRequestHandler` API reference](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/createrequesthandler) for the complete list of required and optional parameters.

***
