ZuploZuplo
LoginSign Up
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop using the Portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingMCP - Quick start
    Develop Locally
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth
Concepts
Development
Policies
Handlers
API Keys
MCP Server
MCP Gateway
AI Gateway
Developer Portal
Monetization
Deploying & Source Control
    Overview
    GitHub
      SetupTesting Deployments
      Custom CI/CD
        Basic DeploymentDeploy and TestPR Preview EnvironmentsLocal Testing in CITag-Based ReleasesMulti-Stage DeploymentAutomatic Cleanup
    GitLab
    Bitbucket
    Azure DevOps
    CircleCI
    Custom CI/CDMonorepo DeploymentRename/Move Project
Observability
Networking & Infrastructure
Account Management
Programming API
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsSecuritySupportTrust & ComplianceChangelog
powered by Zudoku
Custom CI/CD

GitHub Actions: PR Preview Environments

Give every pull request its own Zuplo environment. Reviewers can test changes against a live API, and environments clean up automatically when PRs close.

.github/workflows/pr-workflow.yaml
name: PR Workflow on: pull_request: types: [opened, synchronize, reopened, closed] jobs: deploy-and-test: # Run on PR open/update, not on close if: github.event.action != 'closed' runs-on: ubuntu-latest env: ZUPLO_API_KEY: ${{ secrets.ZUPLO_API_KEY }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm install - name: Deploy to Zuplo id: deploy shell: bash run: | OUTPUT=$(npx zuplo deploy --api-key "$ZUPLO_API_KEY" 2>&1) echo "$OUTPUT" DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -oP 'Deployed to \K(https://[^ ]+)') echo "url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT - name: Run tests run: npx zuplo test --endpoint "${{ steps.deploy.outputs.url }}" - name: Comment PR with deployment URL uses: actions/github-script@v7 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `🚀 Deployed to: ${{ steps.deploy.outputs.url }}` }) cleanup: # Only run when PR is closed (merged or not) if: github.event.action == 'closed' runs-on: ubuntu-latest env: ZUPLO_API_KEY: ${{ secrets.ZUPLO_API_KEY }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm install - name: Delete environment run: | # Environment name is based on branch name BRANCH_NAME="${{ github.head_ref }}" # Convert slashes to hyphens (Zuplo convention) ENV_NAME="${BRANCH_NAME//\//-}" npx zuplo delete \ --environment "$ENV_NAME" \ --api-key "$ZUPLO_API_KEY" \ --wait

This workflow:

  1. On PR open/update: Deploys to an environment named after the branch, runs tests, and comments the URL on the PR
  2. On PR close: Deletes the preview environment

How It Works

  • The environment name comes from the branch name (feature/auth becomes feature-auth)
  • Each push to the PR updates the same environment
  • Closing the PR (merge or abandon) triggers cleanup
  • The PR comment lets reviewers quickly access the preview

Next Steps

  • Add automatic cleanup on branch delete as a backup
  • Implement multi-stage deployment for production releases
Edit this page
Last modified on December 3, 2025
Deploy and TestLocal Testing in CI
On this page
  • How It Works
  • Next Steps
YAML