CI & Automation

Everything the CLI does interactively it also does non-interactively: pass the project and domain as arguments, supply a token instead of logging in, and surge runs prompt-free in any pipeline.

Get a token

On your own machine, where you're logged in:

surge token

Copy the output into your CI provider's secret store as SURGE_TOKEN. The CLI picks that environment variable up automatically—no login step in the pipeline:

SURGE_TOKEN=… surge ./dist example.com

A --token <token> flag is also accepted where an environment variable is awkward. Tokens are long-lived; revoke everything by running surge logout locally, then mint fresh ones.

The non-interactive rule

surge only prompts for information it doesn't have. Give it everything up front and it never asks:

surge ./dist example.com          # path + domain as arguments…
# or
echo example.com > CNAME          # …or domain from the CNAME file
surge ./dist

If a required value is missing and there's no TTY to ask on, the deploy aborts rather than hangs—so a misconfigured pipeline fails fast.

npm scripts

Make deployment part of the project by installing surge as a dev dependency:

npm install --save-dev surge
{
  "scripts": {
    "build": "vite build",
    "deploy": "npm run build && surge ./dist example.com"
  }
}

Now npm run deploy works for everyone on the team (each using their own account, via collaborators), and in CI with SURGE_TOKEN set.

GitHub Actions

name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci && npm run build
      - run: npx surge ./dist example.com
        env:
          SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}

The same shape works in GitLab CI, CircleCI, or any runner with Node available: build, then surge <path> <domain> with SURGE_TOKEN in the environment.

Previews per branch

The preview flow maps naturally onto pull requests—publish every branch build as a preview, and cut over on merge:

# on pull request builds
surge ./dist example.com --preview -m "$COMMIT_MESSAGE"

# on merge to main
surge ./dist example.com

Each PR build gets a stable revision URL to link in the review, and production only moves when main does.

Git hooks

For a lighter-weight setup—no CI service at all—deploy from a local git hook:

echo "surge ./dist example.com" > .git/hooks/post-push
chmod +x .git/hooks/post-push

Or use husky/simple-git-hooks to version the hook with the project.