Ephemeral microservice previews
without duplicating your cluster
Envy deploys only the services you change and reuses the rest from a shared baseline. Test the complete application at your own preview URL.
Your change. The whole application.
Your application is already running.
Start with the services and dependencies you already have.
One service. A new version.
A pull request changes service-b. Build its new container image.
A preview built around your change.
Envy deploys the override and configures your mesh for its preview URL.
Your version. The whole application.
Preview requests use service-b v2 and reuse the other services and shared data.
Previews that fit your stack
Use your existing Kubernetes application, delivery pipeline, and developer tools to test changes together.
Shared Reference Baseline
Deploy selected service versions into a preview. Unchanged services continue running in your approved baseline.
Use your existing mesh
Use Istio, Cilium, or Linkerd to route preview requests to the selected overrides. Your applications propagate standard W3C Baggage between services.
Tools for coding agents
HTTP and stdio MCP tools let coding agents create previews, wait for readiness, inspect logs, and clean up.
Label a PR. Get a preview.
Label a same-repository PR envy-preview. After successful builds, Envy creates its preview, updates it for new commits, and requests cleanup when the PR closes.
Envy CLI & REST API
Create and update previews, inspect logs, and clean up with the CLI or REST API. Integrate the same flow into your CI pipeline.
Connect frontend previews
Point your frontend preview at an Envy backend composition. Bind exact Git commits and record browser verification results for the complete application.
Testing event-driven changes? Google Pub/Sub isolation lets prepared applications capture preview messages and attach consumers later. Topics and databases remain shared.
Create previews your way
Use the envy CLI, MCP tools, or HTTP API to manage the same previews.
CLI and API examples use the local quickstart setup, including authentication and demo images. Returned IDs vary. The catalog tab contains a complete example manifest.
# Create a preview and capture its generated ID (requires Python 3).COMPOSITION_ID=$(envy composition create \ --name pr-checkout-v2 --image envy/service-b:v2 | \ python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])')
envy composition wait "$COMPOSITION_ID" --timeout 60s
# Update the image, then wait for the new generation.envy composition update "$COMPOSITION_ID" \ --expected-generation 1 --image envy/service-b:v3envy composition wait "$COMPOSITION_ID" --timeout 60s
# Fetch a log snapshot and request cleanup.envy composition logs "$COMPOSITION_ID" \ --component service-b --tail-lines 50envy composition destroy "$COMPOSITION_ID"{ "name": "create_composition", "arguments": { "project": "demo", "baseline": "staging", "name": "agent-auth-refactor", "overrides": { "service-b": { "image": "envy/service-b:v2" } }, "ttl": "2h" }}# The API returns JSON with a generated ID and phase "created".curl --fail-with-body -X POST "$ENVY_API_URL/v1/compositions" \ -H "Authorization: Bearer $(cat "$ENVY_API_TOKEN_FILE")" \ -H "Content-Type: application/json" \ -d '{ "project": "demo", "baseline": "staging", "name": "pr-129-preview", "overrides": { "service-b": { "image": "envy/service-b:v2" } }, "ttl": "4h" }'
# Wait for the returned ID before testing its preview URL.# envy composition wait <returned-id> --timeout 60s{ "api_version": "envy/v1", "project": { "id": "shop", "name": "Tea shop" }, "components": [ { "id": "storefront", "project": "shop", "protocol": "http", "port": 8080, "profile": "http-small", "health_path": "/healthz", "readiness_path": "/readyz", "overridable": true, "env": { "SHOP_ROLE": "storefront", "DOWNSTREAM_URL": "http://pricing.envy-shop.svc.cluster.local:8080/products" } }, { "id": "pricing", "project": "shop", "protocol": "http", "port": 8080, "profile": "http-small", "health_path": "/healthz", "readiness_path": "/readyz", "overridable": true, "env": { "SHOP_ROLE": "pricing" } } ], "baseline": { "id": "staging", "project": "shop", "revision": "shop-v1", "endpoint": "http://shop.envy.localhost:8080", "routing": { "namespace": "envy-shop", "gateway": "envy-preview", "entry_component": "storefront" }, "verification": { "kind": "http", "path": "/products", "expected_status": 200 }, "components": { "storefront": { "service_host": "storefront.envy-shop.svc.cluster.local", "port": 8080, "image": "envy/shop:v1" }, "pricing": { "service_host": "pricing.envy-shop.svc.cluster.local", "port": 8080, "image": "envy/shop:v1" } } }}Namespace Duplication vs. Envy
Choose based on how much of the application and its data each preview needs to isolate.
On small screens, scroll the table sideways to compare both approaches.
| Dimension | Namespace / Helm Cloning | Envy Selective Overrides |
|---|---|---|
| Resource OverheadPods & memory per preview | Full Duplication A full clone deploys a separate copy of the application and any included stateful dependencies. | Selective Overrides 0 to 3 services overridden. Unchanged microservices, caches, and storage are shared from baseline. |
| Creation TimeFrom command to live preview URL | Whole application startup Readiness depends on all cloned workloads, volumes, and any database initialization. | Changed service startup The URL is allocated at creation. Use it after workloads, routes, and ingress verification are ready. |
| Data isolationWhere preview writes go | Separate state A separate database can isolate test writes, but needs provisioning and suitable test data. | Live Baseline State Preview writes affect shared baseline data. Use separate test tenants or dedicated data services when isolation is required. |
| AI Agent ToolingAutomation interface | Depends on tooling Typically managed through deployment scripts, CI workflows, or platform APIs. | HTTP & Stdio MCP MCP tools create previews, wait for readiness, fetch logs, and request teardown. Agents run their own tests. |
| Teardown & ExpiryResource reclamation | Lifecycle automation Cleanup depends on the CI or platform lifecycle policy configured for each preview. | TTL-based cleanup Configurable TTL (8h default) and persisted deletion intent. The reconciler retries cleanup when dependencies recover. |
Follow a request through your preview
The services stay connected. Only the workloads you select are replaced.
Both URLs reuse gateway and service-a. The selected mesh selects service-b v2 only when the request carries the matching composition ID. Both service-b versions connect to the same shared data.
Scroll sideways to follow wider branches, or read the connections below.
Read the connections
- Baseline URL → gateway · v1: baseline request.
- Preview URL → gateway · v1: preview request.
- gateway · v1 → service-a · v1: forward baggage.
- service-a · v1 → service-b · v1: no matching context.
- service-a · v1 → service-b · v2: composition=cmp-123.
- service-b · v1 → Database & cache: read / write.
- service-b · v2 → Database & cache: read / write.
Applications forward W3C Baggage between HTTP calls. Your mesh uses that context to choose a destination. Explore the routing contract →