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 --subdomain pr-${{ github.event.number }} --output url)
          echo "preview_url=$PREVIEW_URL" >> $GITHUB_OUTPUT
        env:
          PREV_TOKEN: ${{ secrets.PREV_TOKEN }}
      
      - 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_TOKEN: ${{ secrets.PREV_TOKEN }}

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
    - prev --subdomain mr-$CI_MERGE_REQUEST_IID
  environment:
    name: preview/$CI_MERGE_REQUEST_IID
    url: https://mr-$CI_MERGE_REQUEST_IID.prev.sh
    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 --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 --subdomain pr-123-feature-login

2. Set Appropriate TTLs

Match TTL to your review cycle:

prev --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 --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 status pr-123

View Logs

prev logs pr-123

List All Active Previews

prev list

Conclusion

Automating preview environments with CI/CD is essential for modern development workflows. The configurations provided here should get you started quickly, regardless of which platform you use.

For more advanced configurations and troubleshooting, check out our documentation.