GitHub Actions

Beta

The Catalyst CLI runs without a browser, so you can deploy from CI instead of from a developer’s machine. This page covers two workflows you can add to a Catalyst repository: one that deploys your storefront when a branch merges, and one that deploys a preview for each pull request and comments the URL on it.

Both workflows use the Catalyst CLI from your own repository, so the CLI version stays under your control and upgrades with your project.

The Catalyst CLI is generally available, but Native Hosting is currently in closed beta. There may be breaking changes to the Native Hosting APIs as we finalize them. To express interest in gaining access, fill out the Native Hosting Closed Beta Interest Form.

Prerequisites

You need the following:

  • A Catalyst storefront in a GitHub repository, with @bigcommerce/catalyst 1.2.0 or newer installed. Check with pnpm catalyst --version.
  • The repository already set up for Native Hosting, with the result committed. CI has no terminal to answer the setup prompt, so run setup locally first: scaffold with --hosting commerce, or run pnpm catalyst deploy once and accept the Commerce Hosting setup prompt. Then commit the changes it makes, including middleware.ts and the @opennextjs/cloudflare dependency in package.json.
  • A hosting project to deploy into. Create one with catalyst projects create, then copy its UUID from catalyst projects list.
  • Permission to add secrets and variables to the repository.

Deploying from CI needs credentials that a browser login does not provide, so start by creating an API account for it.

Create an API account for CI

CI has no browser to authenticate through, so unlike a local pnpm catalyst auth login, this account has to be created by hand. See API Accounts for background on store-level vs. app-level accounts before you start.

In your BigCommerce control panel, go to Settings → API accounts → Create API account and choose Store API account. Grant these scopes:

  • Infrastructure Projects — modify
  • Infrastructure Deployments — modify
  • Infrastructure Logs — read-only
  • Channel Settings — modify, if the workflow points a channel at the deployment or sets its checkout URL
  • Sites & Routes — modify, for the same channel and checkout commands

Save the access token. You also need your storefront token, which is the same one your storefront build already uses.

Treat this token as a deployment credential. It can create and replace deployments on your store, so store it as a GitHub secret and never commit it.

Understand the two sets of variables

The Catalyst CLI reads two separate sets of variables, and mixing them up is the most common cause of a failed CI deploy:

  • CLI configuration tells the CLI which store and project to act on, and how to authenticate. In CI, supply CATALYST_ACCESS_TOKEN and CATALYST_PROJECT_UUID as environment variables. There is no CATALYST_STORE_HASH to set — it falls back to BIGCOMMERCE_STORE_HASH. These are never read from .env files, so putting them in .env.local does not authenticate CI.
  • Storefront build variables (BIGCOMMERCE_* and AUTH_SECRET) are read by the Next.js build.

One more distinction matters: a build variable feeds the build running on the runner; it does not reach the deployed application. The deployed worker gets its own environment, which is populated only by --secret flags on catalyst deploy or by values stored with catalyst env add. Values stored with env add live in .bigcommerce/project.json, which isn’t committed, so in CI the --secret flags are the only way to set them. A deployment that builds successfully but returns a runtime configuration error is usually missing a --secret.

For the full resolution order, see Configuration.

Deploy on merge to your default branch

In your GitHub repository, go to Settings → Secrets and variables → Actions. On the Variables tab, add BIGCOMMERCE_STORE_HASH, BIGCOMMERCE_CHANNEL_ID, and CATALYST_PROJECT_UUID. On the Secrets tab, add BIGCOMMERCE_ACCESS_TOKEN, BIGCOMMERCE_STOREFRONT_TOKEN, and AUTH_SECRET.

If your store offers wallet payment methods (such as PayPal) on the cart page, also add BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN on the Secrets tab, and keep the two lines that pass it in the workflow below. It’s the private, Unauthenticated-scoped token Catalyst’s GraphQL proxy uses for those buttons. The build doesn’t need it, so a deploy without it still succeeds, but the buttons fail at runtime. If your store doesn’t offer wallet payment methods, remove those two lines. See BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN for how to create it.

Then create .github/workflows/deploy.yml:

.github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
# A project serves one deployment at a time, so let one deploy finish before
# the next starts rather than racing.
concurrency:
group: catalyst-deploy
cancel-in-progress: false
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
env:
# Tells the CLI which project to deploy to, and how to authenticate.
# The store hash comes from BIGCOMMERCE_STORE_HASH below.
CATALYST_PROJECT_UUID: ${{ vars.CATALYST_PROJECT_UUID }}
CATALYST_ACCESS_TOKEN: ${{ secrets.BIGCOMMERCE_ACCESS_TOKEN }}
# Read by the Next.js build on the runner.
BIGCOMMERCE_STORE_HASH: ${{ vars.BIGCOMMERCE_STORE_HASH }}
BIGCOMMERCE_CHANNEL_ID: ${{ vars.BIGCOMMERCE_CHANNEL_ID }}
BIGCOMMERCE_STOREFRONT_TOKEN: ${{ secrets.BIGCOMMERCE_STOREFRONT_TOKEN }}
AUTH_SECRET: ${{ secrets.AUTH_SECRET }}
# Only needed if your store offers wallet payment methods (such as PayPal)
# on the cart page. Runtime only: passed with --secret below.
BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN: ${{ secrets.BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
# The --secret flags populate the deployed application's environment.
# The env block above only feeds the build.
- name: Deploy
run: |
pnpm catalyst deploy \
--secret "BIGCOMMERCE_STORE_HASH=$BIGCOMMERCE_STORE_HASH" \
--secret "BIGCOMMERCE_STOREFRONT_TOKEN=$BIGCOMMERCE_STOREFRONT_TOKEN" \
--secret "BIGCOMMERCE_CHANNEL_ID=$BIGCOMMERCE_CHANNEL_ID" \
--secret "AUTH_SECRET=$AUTH_SECRET" \
--secret "BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN=$BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN"

Keep the --secret flags in CI. catalyst env add stores values in .bigcommerce/project.json on the machine that runs it, and that file is gitignored, so a CI checkout never has them. Pass every variable your storefront reads at runtime the same way, including optional ones you rely on, such as MAKESWIFT_SITE_API_KEY for Makeswift-connected projects. A missing runtime variable doesn’t fail the deploy; it fails the feature that needs it.

If customers reach your storefront on a hostname other than the one Auth.js derives from the request, sign-in can fail host validation. Pass --secret "AUTH_TRUST_HOST=true" for deployments served on a hostname you control but have not configured as the canonical site URL.

Deploy a preview for each pull request

BigCommerce publishes a GitHub Action that deploys pull request code to a hosting project and comments the URL on the pull request.

Preview deployments are an early version of this feature

A hosting project has one hostname, not one per deployment. A repository therefore shares one preview project and one preview URL, and it serves one pull request at a time. Deploying a preview for a second pull request replaces the first. This behavior may change as the feature develops.

How the shared preview works

The newest open pull request deploys automatically when it receives a push. Any other open pull request claims the preview by commenting redeploy preview on it. When a pull request takes the preview over, the one that previously held it gets a comment explaining that the URL no longer reflects its changes, so no thread is left advertising a stale preview.

Previews do not run for pull requests from forks. The workflow builds and deploys pull request code with your store credentials in scope, so it only runs for branches in your own repository. Only users with write access can run the command.

Create a preview project

Previews need a project of their own. Every preview overwrites the last deployment in it, so do not point previews at the project serving your storefront.

pnpm catalyst projects create
pnpm catalyst projects list

Copy the UUID of the project you created.

Add configuration

In your GitHub repository, go to Settings → Secrets and variables → Actions and add the following. The project UUID, store hash, and channel ID are configuration rather than credentials, so add those on the Variables tab and the rest on the Secrets tab.

NameKindValue
BIGCOMMERCE_PREVIEW_PROJECT_UUIDVariableThe preview project UUID
BIGCOMMERCE_STORE_HASHVariableYour store hash
BIGCOMMERCE_CHANNEL_IDVariableThe channel the preview storefront serves
BIGCOMMERCE_ACCESS_TOKENSecretThe access token from the API account above
BIGCOMMERCE_STOREFRONT_TOKENSecretYour storefront token
AUTH_SECRETSecretGenerate a new value with openssl rand -hex 32

Generate an AUTH_SECRET for previews rather than reusing the one your storefront uses. Sessions then do not carry between a preview and your live storefront.

If BIGCOMMERCE_PREVIEW_PROJECT_UUID is absent, the workflow skips instead of failing, so the feature stays switched off until you configure it.

The preview workflow passes only the access token, storefront token, and AUTH_SECRET to the deployment. It doesn’t accept BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN, so if your store offers wallet payment methods on the cart page, those buttons don’t work on preview deployments. Test those on a deployment that passes the token with --secret, as in Deploy on merge to your default branch.

Add the workflow

Create .github/workflows/preview-deployment.yml:

.github/workflows/preview-deployment.yml
name: Preview Deployment
on:
pull_request:
types: [opened, reopened, synchronize]
issue_comment:
types: [created]
jobs:
preview:
uses: bigcommerce/catalyst/.github/workflows/deployment-preview.yml@preview-action-v1
secrets:
access-token: ${{ secrets.BIGCOMMERCE_ACCESS_TOKEN }}
storefront-token: ${{ secrets.BIGCOMMERCE_STOREFRONT_TOKEN }}
auth-secret: ${{ secrets.AUTH_SECRET }}

That is the whole file. The reusable workflow sets the permissions it needs and serializes deploys across the repository, because all previews share one project.

preview-action-v1 is a moving major tag that tracks the newest 1.x release, so fixes arrive without editing the workflow. To upgrade by hand instead, pin an exact version such as @preview-action-v1.1.0.

A job that calls a reusable workflow cannot declare environment:, and GitHub does not expose environment-scoped secrets to a job that does not. Keep these three secrets at repository level. To scope them to a GitHub Environment, call the action directly instead of the reusable workflow, in a job that declares the environment itself.

Merge the workflow to your default branch

GitHub reads issue_comment workflows from the default branch only. Until this file is merged, commenting redeploy preview does nothing — including on the pull request that adds the file. Pull request previews run from the branch, but the comment command does not.

Use the preview

Open a pull request. If it is the newest open one, it deploys and the action comments the preview URL and the commit it built.

On an older pull request, the action comments that the preview is reserved for the newest one. Comment redeploy preview to claim it. The command gets an eyes reaction while it runs and a rocket when it finishes, and a check named Preview Deployment (redeploy) appears in the pull request’s checks so you can follow progress.

Configuration reference

Pass any of these in the with: block of the reusable workflow.

InputDefaultDescription
project-uuidReads BIGCOMMERCE_PREVIEW_PROJECT_UUIDHosting project every preview deploys into
store-hashReads BIGCOMMERCE_STORE_HASHStore hash
channel-idReads BIGCOMMERCE_CHANNEL_IDChannel the preview storefront serves
environmentNoneGitHub Environment holding your variables
command-phraseredeploy previewComment prefix that claims the preview
auto-deploy-newesttrueSet to false to require the command every time
working-directory.Directory holding the Catalyst project
node-version24Node version used for the build
pnpm-version10The Catalyst CLI shells out to pnpm to build
api-hostapi.bigcommerce.comOverride only for non-production stores
check-namePreview Deployment (redeploy)Check row a redeploy reports against

The workflow also exposes outputs: deployed is "true" when the run deployed, and url holds the preview URL.

Troubleshooting

SymptomCauseWhat to try
The workflow reports as skipped and posts no commentBIGCOMMERCE_PREVIEW_PROJECT_UUID is unset, so previews are switched offAdd the variable, and check the spelling
Missing configuration: naming a secret or variableThe value is scoped to a GitHub Environment that the job does not declareMove it to repository level, or call the action directly from a job that declares the environment
redeploy preview does nothing at allThe workflow is not on your default branchMerge it, then comment again
Client configuration must include a channelId at runtimeA runtime secret did not reach the deployed applicationPass BIGCOMMERCE_CHANNEL_ID with --secret. Values stored with catalyst env add aren’t available in CI.
Cart page wallet buttons fail on the deployed storefront, and /graphql requests are rejectedBIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN did not reach the deployed applicationPass it with --secret. On preview deployments it isn’t supported; see the note under Add configuration.
Previews are not available for pull requests from forksWorking as intendedPush the branch to the repository itself
Your access token is invalid or has expiredThe store API token was revoked or expiredCreate a new token and update BIGCOMMERCE_ACCESS_TOKEN
A 403 naming store_infrastructure_projects_manageThe API account is missing a scopeRecreate it with the scopes listed above
@bigcommerce/catalyst@<version> is older than the required 1.2.0The project’s CLI is too old for the actionUpgrade @bigcommerce/catalyst in your project
The preview URL shows another pull request’s changesAnother pull request claimed the shared previewComment redeploy preview to claim it back

To inspect a failed deployment, stream the project’s logs with catalyst logs.