Preview Environments in CI
How to automate preview environments in your CI pipeline with PR-based keys and header propagation
This guide explains how to automate Preview Environments in your CI pipeline. By integrating mirrord preview with your pull request workflow, each PR gets its own ephemeral environment that reviewers can access via a shared URL and a simple header—no local mirrord setup required.
This feature is available to users on the Enterprise pricing plan.
Flow Overview
On PR open or push: Your CI builds the image(s), pushes to a registry, runs
mirrord preview startwith a stable key (e.g.pr-123), and posts or updates a comment on the PR with the preview URL and the header to use.Reviewers: Open the shared URL and send the header (via the mirrord Browser Extension or
curl). Traffic matching the header is routed to the preview pod.On PR merge or close: CI runs
mirrord preview stop -k <key>to tear down the preview environment.
Choosing the Preview Key
Use a deterministic key tied to the PR so that:
The same key is used across pushes, allowing you to update the PR comment instead of creating duplicates.
Cleanup is straightforward: when the PR closes, you stop the preview by that key.
Best practice: Use the PR number (e.g. pr-123) or a sanitized branch name. In GitHub Actions:
env:
PREVIEW_KEY: "pr-${{ github.event.pull_request.number }}"Automating the PR Comment
Post a comment on the PR that includes:
Preview URL
https://myapp.example.com
Header
X-PG-Tenant: pr-123
Also include instructions for reviewers:
Use the mirrord Browser Extension to set the header for the preview URL, or
Use
curl -H "X-PG-Tenant: pr-123" https://myapp.example.com/api/...
Best practice: Find an existing comment (e.g. by a marker like ## mirrord Preview Environment) and update it on each push, instead of creating a new comment every time. This keeps the PR tidy.
Header Propagation for Backend Testing
When your frontend calls a backend, and the backend calls other services (databases, APIs, queues), the preview header must be propagated so downstream traffic is routed correctly.
1. Configure the Header Filter in mirrord
In your mirrord-preview.json, use {{ key }} in the HTTP filter so only requests with the matching header hit the preview pod:
2. Propagate the Header in Your Application
Read the header from the incoming request, store it in request context, and forward it on all outgoing calls:
HTTP: Add the header to outgoing
http.Requestobjects.gRPC: Add it to
metadatain the outgoing context.Kafka: Add it to message headers.
SQS: Add it to message attributes.
Example (Go with Gin): read X-PG-Tenant, set it in context, then add it to outgoing HTTP and gRPC calls:
If you don't propagate the header, downstream services won't know which preview environment the request belongs to, and traffic may not reach the correct preview pods.
mirrord Configuration
Use the same config file as above (e.g. mirrord-preview.json) per service. The image can be provided in the config or overridden with -i in CI. In CI, pass the image and key via CLI:
CI Workflow Best Practices
Concurrency: Use a concurrency group per PR so that new pushes cancel in-progress runs and avoid duplicate preview pods:
Image tags: Include both PR number and commit SHA for traceability, e.g.
preview-pr-123-abc1234.Cleanup: Always run
mirrord preview stopwhen the PR is closed. Use|| trueso the job doesn't fail if the preview was already stopped or never started:Multiple services: Use the same key for all preview pods in a PR so they form one logical environment. Run
mirrord preview startonce per service, each with-k "pr-123".
Last updated
Was this helpful?

