Other CI/CD Platforms
The official Deploy Walrus Site action targets GitHub Actions only. On any other CI/CD platform, such as GitLab CI/CD, CircleCI, or Bitbucket Pipelines, you drive deployment directly through the site-builder CLI. Because site-builder is a standard Linux binary, the deployment steps are identical on every platform. Only the pipeline syntax differs.
- Prerequisites
- A Sui address funded with SUI (gas fees) and WAL (storage). See Preparing Deployment Credentials.
- The private key in
base64WithFlagformat and the corresponding Sui address. See Exporting your private key. - A CI/CD platform with access to a Linux runner.
How platform-based deployment works
Because there is no pre-built action for non-GitHub platforms, each pipeline must perform the same steps that the GitHub Action handles automatically:
- Reconstruct the Sui configuration: Write the keystore secret from the CI environment to disk so
site-buildercan read it. - Download
site-builder: Fetch the binary for the runner's architecture from the Mysten Labs GCS bucket. - Download
sites-config.yaml: Fetch the network configuration from the walrus-sites repository. - Build the site: Compile or bundle your site output (skip for repositories that already contain deployable static files).
- Run
site-builder deploy: Upload the static output directory to Walrus.
Storing credentials on your platform
Every platform stores secrets differently. In all cases, you need 2 values:
SUI_KEYSTORE: Thebase64WithFlagprivate key string wrapped as a JSON array:["AXXXXXXXXXX..."]. Store this as a masked or protected secret. Never expose it in logs.SUI_ADDRESS: The corresponding Sui address. This is not sensitive, but masking it is acceptable.
| Platform | Secret location |
|---|---|
| GitLab | Settings → CI/CD → Variables (set visibility to Masked) |
| CircleCI | Project Settings → Environment Variables, or a shared Context |
| Bitbucket | Repository settings → Repository variables (enable Secured) |
Never paste SUI_KEYSTORE or any private key directly into a pipeline configuration file. Configuration files are committed to version control and visible to anyone with repository access.
The deploy script
The following shell commands contain all setup and deployment logic. Each platform example below inlines these steps in its own syntax.
#!/usr/bin/env bash
set -euo pipefail
# 1. Reconstruct Sui client configuration from CI secrets.
# SUI_KEYSTORE must be a JSON array string, for example: ["AXXXXX..."]
# Replace 'mainnet' with 'testnet' throughout if targeting Testnet.
WALRUS_NETWORK="${WALRUS_NETWORK:-mainnet}"
mkdir -p ~/.sui/sui_config
echo "$SUI_KEYSTORE" > ~/.sui/sui_config/sui.keystore
cat > ~/.sui/sui_config/client.yaml <<EOF
keystore:
File: "$HOME/.sui/sui_config/sui.keystore"
envs:
- alias: ${WALRUS_NETWORK}
rpc: "https://fullnode.${WALRUS_NETWORK}.sui.io:443"
ws: ~
basic_auth: ~
active_env: ${WALRUS_NETWORK}
active_address: "${SUI_ADDRESS}"
EOF
# 2. Download site-builder for ubuntu-x86_64, which matches standard Linux CI runners.
curl -fsSL \
"https://storage.googleapis.com/mysten-walrus-binaries/site-builder-${WALRUS_NETWORK}-latest-ubuntu-x86_64" \
-o /usr/local/bin/site-builder
chmod +x /usr/local/bin/site-builder
# 3. Download the network-specific sites-config.yaml.
mkdir -p ~/.config/walrus
curl -fsSL \
"https://raw.githubusercontent.com/MystenLabs/walrus-sites/refs/heads/${WALRUS_NETWORK}/sites-config.yaml" \
-o ~/.config/walrus/sites-config.yaml
# 4. Deploy. DIST must point to your built static files directory, not the repository root.
site-builder deploy --epochs "${EPOCHS:-5}" "${DIST:?DIST must be set}"
Set the following environment variables before running the script:
SUI_KEYSTORE: The keystore secret from your platform's secret store.SUI_ADDRESS: The Sui address that corresponds to your keystore.WALRUS_NETWORK:mainnet(default) ortestnet.EPOCHS: Number of storage epochs (default5; maximum53). On Mainnet, 1 epoch is 14 days. On Testnet, 1 epoch is 1 day.DIST: Path to your build output directory, for exampledistorbuild.
Always point site-builder deploy at your build output directory, not your repository root. Uploading the project root includes source files, node_modules/, and other artifacts that significantly increase upload time and storage costs.
Understanding ws-resources.json in pipelines
The site-builder deploy command writes a ws-resources.json file to your DIST directory after the first deployment. This file stores the Sui object ID of your deployed site. On subsequent runs, site-builder reads that ID to update the same site rather than creating a new one.
In a CI/CD pipeline, the build output directory is recreated on every run, so ws-resources.json is lost unless you take one of the following approaches:
- Commit the file to your repository (recommended): Place
ws-resources.jsonin your framework'spublic/directory (or equivalent). Most build tools copy everything inpublic/intoDISTautomatically, making the file available atDIST/ws-resources.jsonon every run without extra configuration. - Pass the object ID explicitly: After the first deployment, copy the
object_idvalue fromws-resources.jsonand store it as a CI variable namedSITE_OBJECT_ID. Then add--object-id "$SITE_OBJECT_ID"to the deploy command:site-builder deploy --object-id "$SITE_OBJECT_ID" --epochs "$EPOCHS" "$DIST".
If neither approach is in place, each pipeline run creates a new site object and incurs additional WAL storage costs.
Platform examples
Store your credentials before adding the pipeline file. Then create the configuration file shown for your platform in your repository root.
- GitLab CI/CD
- CircleCI
- Bitbucket Pipelines
Store SUI_KEYSTORE and SUI_ADDRESS as masked CI/CD variables under Settings → CI/CD → Variables.
Create .gitlab-ci.yml:
stages:
- build
- deploy
variables:
WALRUS_NETWORK: mainnet
EPOCHS: "5"
DIST: dist
build:
stage: build
image: node:lts
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
deploy-walrus:
stage: deploy
image: ubuntu:24.04
needs:
- build
before_script:
- apt-get update -qq && apt-get install -y -qq curl ca-certificates
script:
- mkdir -p ~/.sui/sui_config
- echo "$SUI_KEYSTORE" > ~/.sui/sui_config/sui.keystore
- |
cat > ~/.sui/sui_config/client.yaml <<EOF
keystore:
File: "$HOME/.sui/sui_config/sui.keystore"
envs:
- alias: ${WALRUS_NETWORK}
rpc: "https://fullnode.${WALRUS_NETWORK}.sui.io:443"
ws: ~
basic_auth: ~
active_env: ${WALRUS_NETWORK}
active_address: "${SUI_ADDRESS}"
EOF
- |
curl -fsSL \
"https://storage.googleapis.com/mysten-walrus-binaries/site-builder-${WALRUS_NETWORK}-latest-ubuntu-x86_64" \
-o /usr/local/bin/site-builder
chmod +x /usr/local/bin/site-builder
- |
mkdir -p ~/.config/walrus
curl -fsSL \
"https://raw.githubusercontent.com/MystenLabs/walrus-sites/refs/heads/${WALRUS_NETWORK}/sites-config.yaml" \
-o ~/.config/walrus/sites-config.yaml
- site-builder deploy --epochs "$EPOCHS" "$DIST"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
The build job produces a dist/ artifact that GitLab makes available to the deploy-walrus job through the needs dependency. The rules key restricts both jobs to the default branch, preventing deployments from feature branches.
For static sites with no build step, remove the build stage, remove the needs key from deploy-walrus, and point DIST at your static files directory.
Store SUI_KEYSTORE and SUI_ADDRESS as environment variables under Project Settings → Environment Variables, or in a shared Context if multiple projects share the same deployment address.
Create .circleci/config.yml:
version: 2.1
jobs:
build:
docker:
- image: cimg/node:lts
steps:
- checkout
- restore_cache:
keys:
- node-deps-{{ checksum "package-lock.json" }}
- run:
name: Install dependencies
command: npm ci
- save_cache:
paths:
- node_modules
key: node-deps-{{ checksum "package-lock.json" }}
- run:
name: Build site
command: npm run build
- persist_to_workspace:
root: .
paths:
- dist
deploy:
docker:
- image: cimg/base:current
environment:
WALRUS_NETWORK: mainnet
EPOCHS: "5"
DIST: dist
steps:
- attach_workspace:
at: .
- run:
name: Set up Sui configuration
command: |
mkdir -p ~/.sui/sui_config
echo "$SUI_KEYSTORE" > ~/.sui/sui_config/sui.keystore
cat > ~/.sui/sui_config/client.yaml \<<EOF
keystore:
File: "$HOME/.sui/sui_config/sui.keystore"
envs:
- alias: ${WALRUS_NETWORK}
rpc: "https://fullnode.${WALRUS_NETWORK}.sui.io:443"
ws: ~
basic_auth: ~
active_env: ${WALRUS_NETWORK}
active_address: "${SUI_ADDRESS}"
EOF
- run:
name: Download site-builder
command: |
curl -fsSL \
"https://storage.googleapis.com/mysten-walrus-binaries/site-builder-${WALRUS_NETWORK}-latest-ubuntu-x86_64" \
-o /usr/local/bin/site-builder
chmod +x /usr/local/bin/site-builder
- run:
name: Download sites-config.yaml
command: |
mkdir -p ~/.config/walrus
curl -fsSL \
"https://raw.githubusercontent.com/MystenLabs/walrus-sites/refs/heads/${WALRUS_NETWORK}/sites-config.yaml" \
-o ~/.config/walrus/sites-config.yaml
- run:
name: Deploy to Walrus
command: site-builder deploy --epochs "$EPOCHS" "$DIST"
workflows:
deploy-on-main:
jobs:
- build:
filters:
branches:
only: main
- deploy:
requires:
- build
filters:
branches:
only: main
The persist_to_workspace and attach_workspace steps transfer the build output between the build and deploy jobs, which run on separate containers. The requires key in the workflow ensures deployment runs only after a successful build.
For static sites with no build step, remove the build job, replace attach_workspace with a checkout step in the deploy job, and remove requires from the workflow.
Store SUI_KEYSTORE and SUI_ADDRESS under Repository settings → Repository variables with Secured enabled.
Create bitbucket-pipelines.yml:
image: node:lts
definitions:
steps:
- step: &build-step
name: Build site
caches:
- node
script:
- npm ci
- npm run build
artifacts:
- dist/**
- step: &deploy-step
name: Deploy to Walrus
image: ubuntu:24.04
script:
- apt-get update -qq && apt-get install -y -qq curl ca-certificates
- export WALRUS_NETWORK=mainnet
- export EPOCHS=5
- export DIST=dist
- mkdir -p ~/.sui/sui_config
- echo "$SUI_KEYSTORE" > ~/.sui/sui_config/sui.keystore
- |
cat > ~/.sui/sui_config/client.yaml <<EOF
keystore:
File: "$HOME/.sui/sui_config/sui.keystore"
envs:
- alias: ${WALRUS_NETWORK}
rpc: "https://fullnode.${WALRUS_NETWORK}.sui.io:443"
ws: ~
basic_auth: ~
active_env: ${WALRUS_NETWORK}
active_address: "${SUI_ADDRESS}"
EOF
- |
curl -fsSL \
"https://storage.googleapis.com/mysten-walrus-binaries/site-builder-${WALRUS_NETWORK}-latest-ubuntu-x86_64" \
-o /usr/local/bin/site-builder
chmod +x /usr/local/bin/site-builder
- |
mkdir -p ~/.config/walrus
curl -fsSL \
"https://raw.githubusercontent.com/MystenLabs/walrus-sites/refs/heads/${WALRUS_NETWORK}/sites-config.yaml" \
-o ~/.config/walrus/sites-config.yaml
- site-builder deploy --epochs "$EPOCHS" "$DIST"
pipelines:
branches:
main:
- step: *build-step
- step: *deploy-step
Bitbucket Pipelines passes artifacts declared in one step to the next step in the same pipeline automatically. The dist/** pattern makes the build output available to the deploy step without any additional workspace configuration.
For static sites with no build step, remove *build-step from the main branch pipeline. Change the deploy step's image to one that includes curl and ca-certificates, or add the apt-get install line.
Adapting to any other platform
Any CI/CD platform that provides Linux runners can deploy Walrus Sites using the same pattern. The following table maps the concepts from the 3 examples above to their equivalents on other platforms:
| Concept | GitLab | CircleCI | Bitbucket | General approach |
|---|---|---|---|---|
| Secret storage | CI/CD Variables (Masked) | Environment Variables or Context | Repository variables (Secured) | Platform secret store |
| File sharing between jobs | artifacts + needs | persist_to_workspace + attach_workspace | artifacts (automatic) | Platform artifact or cache mechanism |
| Branch restriction | rules on $CI_DEFAULT_BRANCH | filters on branch name | branches key | Push trigger scoped to main branch |
| Runner image | image: per job | docker: executor per job | image: per step | Any Ubuntu-based Linux image |
The deploy script itself does not change between platforms. Copy the 5-step script from The deploy script section and inline it into your platform's job definition using that platform's multiline script syntax.