GitHub Action
A GitHub Action that puts your static site live on every push. Supports PR previews, custom domains, and self-expiring deployments — and you can try it before creating an account. Marketplace / GitHub / example recipes
- uses: shipstatic/action@v2
with:
token: ${{ secrets.SHIP_TOKEN }} # your API key, stored as a secret
path: ./dist
Start without an account
In your repository, create a file called .github/workflows/deploy.yml:
name: Deploy
on: push
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: npm ci && npm run build
- uses: shipstatic/action@v2
with:
path: ./dist
Commit, push, and open the run in the Actions tab: the run's summary shows your site's address, live the moment the job goes green. Deploys made without a token are public and expire — the summary shows the exact date, and a claim link that keeps the site permanently on a free account. (Deploying a plain folder with no build step? Delete the run: line and use path: ..)
Deploy to your account
- Get your API Key at my.shipstatic.com/api-key.
- In your repository: Settings → Secrets and variables → Actions → New repository secret. Name it
SHIP_TOKEN, paste the key. - Add
token:to the deploy step:
- uses: shipstatic/action@v2
with:
token: ${{ secrets.SHIP_TOKEN }}
path: ./dist
Deployments now land in your account and never expire.
Your domain, previews included
The production pattern in one workflow — pushes to main deploy to your domain, pull requests get previews with a comment:
name: Deploy
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: npm ci && npm run build
- uses: shipstatic/action@v2
with:
token: ${{ secrets.SHIP_TOKEN }}
path: ./dist
domain: ${{ github.event_name == 'push' && 'www.example.com' || '' }}
When domain is set, the deploy and the link are one operation: the site is live at that address when the action finishes, and the url output is your domain's URL. The expression above links the domain on push and skips it for pull requests, so PRs stay previews. A domain with no token is refused before anything is uploaded — a domain belongs to an account.
PR previews
On a pull request the action posts the deployment URL as a comment, updated in place on every push rather than adding a new one. This needs no configuration — github-token defaults to the workflow's own token — only the pull-requests: write permission. Pass github-token: '' to turn comments off.
For previews that clean themselves up, add a ttl.
Self-expiring deployments
ttl gives a deployment a lifetime in seconds, after which the platform reclaims it — previews that need no cleanup workflow, no pull_request: closed handler:
ttl: 604800 # one week
It needs a token (a deployment made without one already expires on its own schedule) and cannot be combined with domain: a domain should not point at something about to be reclaimed. The expires output carries the deadline.
GitHub Deployments
Declare an environment: on your job and GitHub records the deployment itself, with the environment you named. The action does not write one.
Authentication
One slot. token accepts either credential the platform issues: an API Key (ship-…) or a deploy token (deploy-…). Store it as a repository secret and pass it as token.
Linking a domain needs an API key specifically: a deploy token is scoped to creating deployments and nothing else.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
token |
No | - | Your API Key (ship-…), or a deploy token (deploy-…) — one slot takes either. Omit to deploy anonymously |
api-url |
No | the CLI's | API endpoint. Leave unset for production |
path |
No | . |
Directory to deploy |
domain |
No | - | Domain to serve the deployment at — deployed and linked in one step (requires an API key in token) |
ttl |
No | - | Seconds until the deployment expires and is cleaned up automatically (requires token; cannot be combined with domain) |
password |
No | - | Password-protect the deployment (6–128 characters). Visitors are prompted to unlock before viewing |
labels |
No | - | Comma-separated labels, added to the commit short SHA the action applies automatically |
idempotency-key |
No | derived | Override the derived key. Defaults to this workflow run + job, so re-running a job replays the original deployment instead of deploying twice |
github-token |
No | the workflow's own token | GitHub token for the PR comment. Pass an empty string to post no comment |
Outputs
| Output | Description |
|---|---|
deployment |
Deployment host (e.g. happy-cat-abc1234.shipstatic.com) |
url |
URL of the deployed site — your domain's URL when domain is set, otherwise the deployment's own (e.g. https://happy-cat-abc1234.shipstatic.com) |
claim |
Claim URL for public deploys — visit while signed in to keep the site permanently. Empty for authenticated deploys |
expires |
Expiry as a unix timestamp in seconds. Set for public deploys and for any deployment given a ttl |
Every deploy also writes a summary to the workflow run page — the deployment and its URL, plus the claim link and expiry where the deployment has them. Nothing to configure, and nothing to add.
Use outputs in subsequent steps:
- name: Notify
run: echo "Deployed to ${{ steps.deploy.outputs.url }}"
Permissions
The PR comment is the only thing the action needs a permission for:
permissions:
contents: read
pull-requests: write
Examples
Five annotated, copy-pasteable workflows in the action-example repo — no account, API key, custom domain, PR previews, and password protection. Each file explains every line to a first-time reader.
Architecture
Composite action wrapping the CLI. Installs @shipstatic/ship at runtime, runs ship commands, and parses JSON output. No custom code beyond shell scripts.