A per-PR preview URL is a link, posted on the pull request, that opens a running version of the application with that change included. Anyone with the link can try the feature before it merges, without pulling a branch or building anything. Frontend platforms made this a default expectation, and the question most teams face is how to get the same experience for services running on Kubernetes.
The short answer is that the URL is the visible end of an environment strategy. For a frontend, the environment is a self-contained build artifact, so a URL per PR is nearly free. For a backend service, the PR’s code is one node in a graph of services and datastores, so the URL has to lead to a place where that whole graph exists. The approaches below differ mainly in how they produce that place.
Vercel and Netlify build every pull request and comment a unique link on it, using URL schemes like a per-PR subdomain. The pattern works because the deliverable is a static or serverless bundle. Each build is complete in itself, hosting is a content delivery network (CDN) push, and a thousand previews cost little more than one.
That mental model is what most searchers arrive with. It sets the right expectation for the workflow, a link on every PR that product managers and designers can click, and the wrong expectation for the mechanics once real backends are involved.
A backend pull request has nothing to show by itself. To render a page or serve an API response, the changed service needs its upstream callers, its downstream dependencies, a database with plausible data, and often a message queue. The unit that must exist behind the preview URL is the system, not the artifact.
That leaves two basic strategies. Either you stand up a copy of the system for every pull request, or you share one live system and arrange for the PR’s requests to hit the changed service. Everything else in this article is a variation on those two moves.
CI or a GitOps controller deploys the entire stack into a namespace per pull request, and a wildcard Domain Name System (DNS) record plus an ingress rule map pr-123.preview.example.com to it. Tools like ExternalDNS automate the records. This is the backend equivalent of the frontend pattern. Okteto and Release sell managed versions of it, and the Argo CD ApplicationSet pattern is the common way teams build it themselves.
It is conceptually clean because each preview is fully self-contained. Nothing is shared, so there are no routing rules to reason about, no header propagation to verify, and no way for one preview to interfere with another. Debugging an environment means looking at one namespace. But it gets expensive in proportion to system size and PR volume, since every open PR carries a full copy of every service, sitting mostly idle. Twenty open PRs against a thirty-service stack means six hundred running containers before anyone clicks a link. Each of those environments is also something the platform team operates: seeding its data, keeping its config current, and answering for it when a preview comes up broken. Spin-up time grows with the stack too, since the preview is not ready until the slowest service and its data are, and once previews take minutes to build, teams start rationing them to the risky changes, which quietly defeats the point of a preview on every PR.
The alternative keeps one stable environment running and deploys only the services a PR changed, whether that is one service or several, as isolated versions alongside their stable counterparts. Requests that carry the PR’s routing key in a header are routed to the changed services at each hop, and fall through to the stable versions of everything else. One link virtualizes the full stack for that PR without deploying it. The preview URL is a hosted address that injects the routing key on every request, so clicking the link is all a reviewer does differently.
This is the architecture behind Signadot’s Sandboxes, lightweight ephemeral environments that hold the changed service inside the shared cluster. Each Sandbox endpoint gets a hosted preview URL that injects the routing key automatically and authenticates through the control plane, so reviewers signed into the dashboard open it in a browser while automation uses an API key (see the preview URL reference).
The biggest win is developer experience. A preview is ready as soon as one container starts, in seconds, and that stays true whether the stack has five services or three hundred, because nothing else needs to be deployed. Every preview also exercises the real, current versions of every dependency rather than a copy that may have drifted. Fast, dependable links are what keep reviewers and product managers clicking on every PR instead of saving previews for the risky changes.
The operational and cost profile follows from the same property. The platform team keeps one baseline environment in sync with the main branch instead of operating a fleet of full copies, each needing data seeding, config updates, and an on-call answer when it comes up broken. And each preview costs one service instance rather than one system copy; this walkthrough of cost-efficient preview environments shows how that changes the bill in detail. The prerequisite is that services propagate request headers across hops, which teams with distributed tracing already do.
The same preview URLs verify behavior for web and mobile applications alike, including mobile and frontend previews driven by backend changes. They also pair with frontend platforms, shown in this Vercel plus Kubernetes preview tutorial.
Signadot gives each pull request a hosted preview URL backed by a lightweight sandbox on your shared cluster, so reviewers click a link and see the change running against real dependencies. The free tier is open to every developer.
Start for freeThe people a preview URL is for usually cannot run kubectl, so access has to work at the browser level. The common answers:
Managed platforms handle this at their control plane, authenticating the hosted preview URL against the user’s existing session. Whichever you choose, the test is whether a product manager can open the link from the PR with zero setup.
Data matters as much as access. A preview backed by an empty database demos nothing, so environments either share the stable system’s data through the routing approach, or seed fixtures on creation in the duplication approach. Shared data with isolated writes is its own topic, and the preview environments guide covers the options in depth.
Cleanup is the part teams forget until it shows up on the cluster bill. Preview environments should tear down when the PR merges or closes, with a time-to-live backstop for anything that leaks. In the routing model, cleanup is deleting the ephemeral environment. In the duplication model, it is deleting a namespace and its volumes.
The URL only changes behavior if nobody has to go looking for it. The standard wiring is a CI step that creates the preview and comments the link on the pull request, GitHub Actions and GitLab CI both make this a few lines, and many teams also post it to the ticket and the team channel. Some add a commit status or check run that links to the preview, so the URL sits in the merge box itself.
Two small details pay off:
Step by step:
Reviewers are not always human. Coding agents can open the same preview to run end-to-end tests against the change before anyone looks at it, which makes the preview URL the validation surface for agent-written code as much as for human review.
The choice is really about a tipping point. A team with a small stack and moderate PR volume has no bottleneck to fix. A namespace per PR is the simpler approach, cost and spin-up time are tolerable at that scale, and the whole mechanism stays easy to reason about. There is no reason to add a routing layer before the economics demand one.
The calculus changes as the team and the service graph grow. When spin-up time gets long enough that stakeholders stop clicking, when the platform team spends its weeks keeping preview copies alive instead of improving the platform, or when the preview bill becomes a line item that needs explaining, duplication has hit its ceiling. At that point header-based routing stops being an optimization and becomes the requirement for PR previews to keep scaling: previews stay seconds from ready and at the cost of the changed services, no matter how large the stack grows or how many PRs are open.
Both deliver the thing that changes how teams review, a URL on every pull request that anyone can click, and the preview environments solution page covers what the managed version of that workflow looks like.
A per-PR preview URL is a link, posted on the pull request, that opens a running version of the application with that change included. Anyone with the link, a reviewer, QA, or a product manager, can try the change before it merges without pulling a branch or building anything locally.
A frontend preview deploys one self-contained build artifact to a CDN, so a URL per PR is nearly free. A backend change has nothing to show by itself: it needs its upstream callers, downstream dependencies, a database with plausible data, and often a message queue. The preview URL has to lead to a full working system, not a single artifact.
Either duplicate the environment per PR, deploying the full stack into its own namespace behind a per-PR subdomain, or keep one shared baseline environment, deploy only the changed services, and route requests carrying the PR's routing key to them at each hop. Duplication is simpler at small scale; header-based routing keeps previews ready in seconds, spares the platform team from operating a fleet of environment copies, and keeps cost flat as the stack and PR volume grow.
Get the latest updates from Signadot