Skip to content

Deployment to Shopify Oxygen

Overview

Shopify Oxygen is an edge hosting platform built on Cloudflare Workers. It provides:

  • Global edge deployment — Low latency worldwide via Cloudflare's network
  • Automatic scaling — No capacity planning needed
  • CI/CD integration — Two GitHub Actions workflows deploy automatically on every push
  • Environment management — Preview and production environments with variable inheritance

Deployment Architecture

┌─────────────────────────────────────────────────────────────────┐
│                     GitHub Repository                           │
│                            │                                    │
│                       git push                                  │
│                            ▼                                    │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │           GitHub Actions (TWO workflows)                 │   │
│  │  oxygen-deployment-1000042728.yml (Storefront A)        │   │
│  │  oxygen-deployment-1000083568.yml (Storefront B)        │   │
│  │                                                          │   │
│  │  1. Checkout code                                        │   │
│  │  2. Setup Node.js (LTS)                                  │   │
│  │  3. Cache & install dependencies (npm ci)                │   │
│  │  4. Build & Deploy (shopify hydrogen deploy)             │   │
│  └─────────────────────────────────────────────────────────┘   │
│                            │                                    │
│                            ▼                                    │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                   Shopify Oxygen                         │   │
│  │                                                          │   │
│  │   ┌─────────────┐    ┌─────────────┐                   │   │
│  │   │  Preview     │    │ Production  │                   │   │
│  │   │ Environment  │    │ Environment │                   │   │
│  │   └─────────────┘    └─────────────┘                   │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

GitHub Actions Workflows

UberLotto uses two Oxygen deployment workflows. Both trigger on every push to any branch, and Shopify Oxygen automatically determines whether to deploy to production (main branch) or a preview environment (other branches).

Workflow 1: Storefront 1000042728

File: .github/workflows/oxygen-deployment-1000042728.yml

yaml
name: Storefront 1000042728
on: [push]

permissions:
  contents: read
  deployments: write

jobs:
  deploy:
    name: Deploy to Oxygen
    timeout-minutes: 30
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup node.js
        uses: actions/setup-node@v4
        with:
          node-version: "lts/*"
          check-latest: true

      - name: Cache node modules
        id: cache-npm
        uses: actions/cache@v4
        env:
          cache-name: cache-node-modules
        with:
          path: ~/.npm
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      - name: Install dependencies
        run: npm ci

      - name: Build and Publish to Oxygen
        run: npx shopify hydrogen deploy
        env:
          SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN: ${{ secrets.OXYGEN_DEPLOYMENT_TOKEN_1000042728 }}

Workflow 2: Storefront 1000083568

File: .github/workflows/oxygen-deployment-1000083568.yml

Identical structure to Workflow 1 but uses its own deployment token:

yaml
name: Storefront 1000083568
on: [push]
# ... same steps ...
      - name: Build and Publish to Oxygen
        run: npx shopify hydrogen deploy
        env:
          SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN: ${{ secrets.OXYGEN_DEPLOYMENT_TOKEN_1000083568 }}

Why Two Workflows?

Each workflow targets a different Shopify storefront environment. This enables deploying the same codebase to multiple storefronts (e.g., staging and production stores, or regional storefronts) from a single repository.

Required GitHub Secrets

Configure these in GitHub Repository → Settings → Secrets and variables → Actions:

SecretDescription
OXYGEN_DEPLOYMENT_TOKEN_1000042728Deployment token for Storefront 1000042728
OXYGEN_DEPLOYMENT_TOKEN_1000083568Deployment token for Storefront 1000083568

Getting Deployment Tokens

  1. Navigate to Shopify Admin → Sales channels → Hydrogen
  2. Select the target storefront
  3. Go to Settings → Deployment
  4. Copy the deployment token

Branch Strategy

BranchEnvironmentURL
mainProductionCustom domain / .myshopify.com
Any other branchPreviewUnique preview URL per deployment
main (production)

  ├── develop (staging/preview)
  │     │
  │     ├── feature/xxx
  │     └── bugfix/xxx

  └── hotfix/xxx (urgent fixes)

WARNING

Both workflows trigger on every push to any branch. Shopify Oxygen determines the environment (production vs. preview) based on the branch configuration in your Shopify admin.

Manual Deployment

Prerequisites

bash
# Ensure you're logged into Shopify CLI
shopify auth login

# Link to your store (if not already linked)
shopify hydrogen link

Deploy Command

bash
# Build and deploy to Oxygen
npm run build && npx shopify hydrogen deploy

Preview Deployment

bash
# Deploy to preview environment
npx shopify hydrogen deploy --preview

Environment Variables in Oxygen

Setting Variables via Shopify Admin

  1. Shopify Admin → Sales channels → Hydrogen
  2. Select storefront → Settings → Environment variables
  3. Add or edit variables

Setting Variables via CLI

bash
# Push local .env to Oxygen
shopify hydrogen env push

# Pull Oxygen env to local
shopify hydrogen env pull

# List current environment variables
shopify hydrogen env list

Variable Inheritance

Production Environment


┌───────────────────┐
│ Base Variables     │ ← Set at storefront level
│ (shared)           │
└───────┬───────────┘

   ┌────┴────┐
   ▼         ▼
┌──────┐  ┌───────┐
│ Prod │  │Preview│ ← Can override base variables
└──────┘  └───────┘

Key Environment Variables

The application requires the following environment variables configured in Oxygen:

CategoryVariables
ShopifyPUBLIC_STORE_DOMAIN, PUBLIC_STOREFRONT_API_TOKEN, PUBLIC_CHECKOUT_DOMAIN
SupabaseSUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY
PlisioPLISIO_API_KEY, PLISIO_SECRET_KEY
MoonPayMOONPAY_SECRET_KEY, MOONPAY_WEBHOOK_KEY
AnalyticsVITE_PUBLIC_POSTHOG_KEY, VITE_PUBLIC_POSTHOG_HOST
Cron/SecurityCLEANUP_SECRET_TOKEN

DANGER

Never commit secrets to the repository. Always configure sensitive values through Shopify Admin or shopify hydrogen env push.

Build Process

What Happens During Build

  1. Shopify Codegen — Generates GraphQL types from queries

    bash
    shopify hydrogen codegen
  2. Vite Build — Bundles the application for production

    bash
    vite build
  3. Asset Processing

    • CSS minification (Tailwind CSS v4)
    • JavaScript minification and tree-shaking
    • PWA manifest generation
    • Service worker compilation (via vite-plugin-pwa)

Build Output

dist/
├── client/
│   ├── assets/              # Hashed static assets
│   ├── manifest.webmanifest # PWA manifest
│   └── sw.js                # Service worker
└── worker/
    └── index.js             # Edge worker bundle

Monitoring Deployments

GitHub Actions

  • View workflow runs: Repository → Actions tab
  • Both workflows run in parallel on each push
  • Check deployment status and logs per workflow
  • Re-run failed deployments individually

Shopify Admin

  • Deployment history: Hydrogen → Deployments
  • View preview URLs for non-main branches
  • Monitor deployment status in real-time

Rollback Procedure

Via Shopify Admin

  1. Navigate to Hydrogen → Deployments
  2. Find the previous successful deployment
  3. Click "Rollback to this version"

Via Git

bash
# Safe rollback: revert the last commit
git revert HEAD
git push origin main

DANGER

Avoid force-pushing to main. Use git revert to create a new commit that undoes changes, preserving history and enabling both workflows to redeploy the previous state.

Performance Optimization

Edge Caching

Oxygen automatically caches static assets (JS, CSS, images). For dynamic content, set cache headers in loaders:

typescript
export async function loader() {
  return data(result, {
    headers: {
      'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
    },
  });
}

Bundle Analysis

bash
# Analyze bundle size
npm run build -- --analyze

Troubleshooting

Deployment Timeout

Symptom: Build exceeds the 30-minute timeout.

Solutions:

  • Check for infinite loops in build scripts
  • Reduce dependency count
  • npm caching is already configured in both workflows

Missing Environment Variables

Symptom: Runtime errors about undefined variables.

bash
# Verify variables are set in Oxygen
shopify hydrogen env list

# Push missing variables
shopify hydrogen env push

Build Failures

Symptom: TypeScript or bundling errors in CI.

bash
# Validate locally before pushing
npm run typecheck
npm run lint
npm run build

PWA Assets Not Found

Symptom: 404 errors for manifest or service worker.

  • Verify files exist in public/ directory
  • Check vite.config.ts for correct PWA plugin configuration

Workflow-Specific Failures

If one workflow succeeds but the other fails, check that both deployment tokens are valid and not expired. Each storefront requires its own token.

UberLotto Technical Documentation