Integrating preview environments into your CI/CD pipeline automates the deployment process and ensures every pull request gets a live preview URL. This article covers best practices and provides ready-to-use configurations for popular CI/CD platforms.

Why Automate Preview Deployments?

Manual preview deployments defeat the purpose of rapid iteration. By automating the process, you:

  • Save time: No manual intervention required for each PR
  • Ensure consistency: Every PR gets the same treatment
  • Enable parallel workflows: Multiple PRs can have simultaneous previews
  • Improve traceability: Preview URLs are automatically linked to PRs

GitHub Actions Integration

GitHub Actions is one of the most popular CI/CD platforms. Here's a complete workflow for automated preview deployments:

Basic Workflow

name: Preview Environment

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build project
        run: npm run build
      
      - name: Deploy to prev
        id: deploy
        run: |
          curl -fsSL https://prev.sh/install.sh | sh
          PREVIEW_URL=$(prev create . --subdomain pr-${{ github.event.number }} -o url)
          echo "preview_url=$PREVIEW_URL" >> $GITHUB_OUTPUT
        env:
          PREV_API_KEY: ${{ secrets.PREV_API_KEY }}
      
      - name: Comment on PR
        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: '🚀 Preview deployed: ${{ steps.deploy.outputs.preview_url }}'
            })

Cleanup on PR Close

name: Cleanup Preview

on:
  pull_request:
    types: [closed]

jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - name: Destroy preview
        run: |
          curl -fsSL https://prev.sh/install.sh | sh
          prev destroy pr-${{ github.event.number }}
        env:
          PREV_API_KEY: ${{ secrets.PREV_API_KEY }}

GitLab CI Integration

For GitLab users, here's an equivalent configuration:

stages:
  - deploy
  - cleanup

deploy_preview:
  stage: deploy
  image: node:20
  script:
    - npm ci
    - npm run build
    - curl -fsSL https://prev.sh/install.sh | sh
    - PREVIEW_URL=$(prev create . --subdomain mr-$CI_MERGE_REQUEST_IID -o url)
    - echo "Preview deployed: $PREVIEW_URL"
  environment:
    name: preview/$CI_MERGE_REQUEST_IID
    on_stop: stop_preview
  rules:
    - if: $CI_MERGE_REQUEST_IID

stop_preview:
  stage: cleanup
  image: node:20
  script:
    - curl -fsSL https://prev.sh/install.sh | sh
    - prev destroy mr-$CI_MERGE_REQUEST_IID
  environment:
    name: preview/$CI_MERGE_REQUEST_IID
    action: stop
  rules:
    - if: $CI_MERGE_REQUEST_IID
      when: manual

CircleCI Integration

version: 2.1

jobs:
  deploy-preview:
    docker:
      - image: cimg/node:20.0
    steps:
      - checkout
      - run:
          name: Install dependencies
          command: npm ci
      - run:
          name: Build
          command: npm run build
      - run:
          name: Deploy preview
          command: |
            curl -fsSL https://prev.sh/install.sh | sh
            prev create . --subdomain pr-$CIRCLE_PR_NUMBER

workflows:
  preview:
    jobs:
      - deploy-preview:
          filters:
            branches:
              ignore: main

Best Practices

1. Use Semantic Subdomain Names

Include identifiable information in your subdomain:

prev create . --subdomain pr-123-feature-login

2. Set Appropriate TTLs

Match TTL to your review cycle:

prev create . --ttl 3d  # Most PRs are reviewed within 3 days

3. Secure Your Tokens

Never commit API tokens. Use CI/CD secrets:

  • GitHub: Repository Settings → Secrets
  • GitLab: Settings → CI/CD → Variables
  • CircleCI: Project Settings → Environment Variables

4. Handle Build Failures Gracefully

Add error handling to prevent silent failures:

- name: Deploy preview
  run: |
    prev create . --subdomain pr-${{ github.event.number }} || {
      echo "Preview deployment failed"
      exit 1
    }

5. Add Status Checks

Require preview deployment as a status check before merging.

Monitoring and Debugging

Check Deployment Status

prev list

View Logs

prev logs pr-123

List All Active Previews

prev list

Conclusion

Automating preview environments with CI/CD removes manual deploy steps from review workflows. The configurations here are starting points for GitHub Actions, GitLab CI, and CircleCI.

For CLI flags, cleanup commands, and troubleshooting, check out the CLI Commands documentation.