Docs/ Deployment/ Preview Environments

Preview Environments

Every pull request gets its own live deployment with a unique URL. Review changes in a real environment before merging, then clean up automatically when the PR is closed.

What Are Preview Environments

Preview environments are temporary, fully functional deployments created automatically for every pull request. They allow you to test changes in an isolated environment that mirrors production, without affecting your live application.

When a team member opens a PR, sh0 builds the branch, deploys it to a unique URL, and posts a comment on the PR with a link to the preview. When the PR is merged or closed, the preview environment is automatically destroyed.

GitHub pull request with an sh0 bot comment showing the preview URL and deploy status

Enabling Previews

Preview environments are enabled per app. Navigate to App Settings → Git → Preview Environments and toggle the feature on. You will need a connected Git provider (GitHub, GitLab, or Bitbucket) with webhook access.

Preview environment toggle in app settings

Once enabled, sh0 listens for pull request events from your Git provider:

  • PR opened: Build and deploy the branch
  • PR updated (new push): Rebuild and redeploy
  • PR merged or closed: Destroy the preview environment
Note
Preview environments require your Git provider to be connected via OAuth so that sh0 can receive PR events and post status updates. Manual webhook setups do not support preview environments.

Automatic PR Deploys

When a pull request is opened, sh0 automatically:

  1. Clones the PR branch
  2. Builds a Docker image using the same build pipeline as production
  3. Starts a new container with the PR code
  4. Assigns a unique preview URL
  5. Posts a comment on the PR with the preview link and build status
  6. Updates the PR status check (green checkmark or red cross)
Deployment in progress for a pull request with real-time build log

When new commits are pushed to the PR branch, sh0 automatically rebuilds and redeploys the preview. The URL stays the same, so reviewers always see the latest version.

Tip
You can configure sh0 to only build previews for PRs targeting specific branches (e.g., only PRs into main). This prevents unnecessary builds for PRs between feature branches.

Preview URLs

Each preview environment receives a unique URL based on the branch name and app name:

Preview URL format
https://{branch-name}.{app-name}.your-domain.com

For example, if your app is named my-api and the PR branch is feature/new-auth, the preview URL would be:

Example preview URL
https://feature-new-auth.my-api.sh0.app

Branch names are sanitized for use in URLs: slashes are replaced with hyphens, and special characters are removed. SSL certificates are provisioned automatically for each preview URL via Caddy.

Note
If you use a wildcard DNS record for your domain (e.g., *.my-api.your-domain.com), preview URLs work immediately. Otherwise, sh0 provisions individual DNS records for each preview.

Preview Environment Settings

You can customize how preview environments behave:

  • Base branch filter: Only build previews for PRs targeting specific branches
  • Environment variable overrides: Set preview-specific variables (e.g., NODE_ENV=staging)
  • Resource limits: Limit CPU and memory for preview containers to save resources
  • TTL (time to live): Automatically destroy previews after a specified duration, even if the PR is still open
  • Max concurrent previews: Limit the number of active preview environments to control resource usage
Preview environment settings panel with filters, resource limits, and TTL configuration

Auto-Cleanup

When a pull request is merged or closed, sh0 automatically cleans up the preview environment:

  1. The preview container is stopped and removed
  2. The Docker image is deleted to free disk space
  3. The Caddy route is removed
  4. The SSL certificate is cleaned up
  5. Any preview-specific volumes are deleted (unless configured to persist)

You can also manually destroy a preview environment from the dashboard without closing the PR. This is useful if a preview is consuming resources and is no longer needed for review.

Warning
Preview environment data (databases, file uploads) is ephemeral by default. If your preview environments need seed data, use a pre-deploy hook to populate the database on each deploy.

Database Isolation

Preview environments can be configured to use isolated databases. sh0 supports two strategies:

  • Shared database: Preview environments connect to the same database as staging or production (read-only recommended). Set this via environment variable overrides.
  • Isolated database: sh0 spins up a dedicated database container for each preview. The database is seeded from a snapshot or migration script and destroyed with the preview.
Preview environment with isolated database
preview:
  enabled: true
  database_isolation: true
  seed_command: "pg_restore --dbname=$DATABASE_URL /seeds/staging.dump"
  max_concurrent: 5
  ttl: 72h
Tip
For the best review experience, combine preview environments with isolated databases and seed data from your staging environment. This gives reviewers a realistic preview of how changes will behave in production.