Service connections
Explicit edges between deployments; with optional env var injection that ZopDay keeps fresh.
A service connection is an explicit, declared edge between two deployments in the same environment. ZopDay uses these for two things: rendering the architecture canvas correctly, and (optionally) keeping a downstream service’s connection URL injected as an environment variable on the consumer, refreshed when the target moves.
What a connection looks like
A connection carries:
| Field | What it is |
|---|---|
id | UUID |
env_id | The environment both deployments live in. Connections cannot cross environments. |
source_deployment_id | The consumer (the one reading the URL). |
target_deployment_id | The producer (the one being read). |
injected_var | Optional. The env var name on the consumer that should receive the target’s connection URL. |
created_at / updated_at | Standard timestamps. |
If injected_var is unset, the connection is visualisation-only: it appears as an edge on the architecture canvas, and that’s it. If injected_var is set, ZopDay actively manages an env var on the consumer.
When to add a connection
The honest answer: usually not until something forces you to. Service-to-service communication works fine without connections if you’ve hard-coded the target URL in the consumer’s config. Connections become useful when:
- You want the architecture canvas to show the topology accurately (without manually drawing arrows)
- The target’s URL changes over time (LB reassignment, datastore failover, blue/green flip) and you want the consumer to pick up the new URL without a redeploy
- Your CI is constantly rewriting consumer configs to point at the right target; connections do that for you
Visualisation-only connections
The simplest case: declare a connection without injected_var.
POST /orgs/{orgID}/environments/{envID}/deployments/connections{ "sourceDeploymentId": "<consumer-uuid>", "targetDeploymentId": "<producer-uuid>"}This adds an edge on the canvas. No env vars are touched on either deployment. Delete it with DELETE /orgs/{orgID}/environments/{envID}/deployments/connections/{connectionID}.
Connections with env var injection
Set injectedVar to the name your code expects. The variable name is whatever you want. ZopDay does not impose a naming convention (per the no_forced_syntax rule).
POST /orgs/{orgID}/environments/{envID}/deployments/connections{ "sourceDeploymentId": "<api-server-uuid>", "targetDeploymentId": "<redis-uuid>", "injectedVar": "REDIS_URL"}What happens after this:
- ZopDay reads the target deployment’s connection URL; typically the cluster-internal service DNS (
<service>.<namespace>.svc.cluster.local:<port>) or, for datastores, the cloud-side endpoint. - ZopDay injects
REDIS_URL=<value>into the consumer’s container env on the next deploy. - ZopDay keeps the env var fresh. If the target’s connection URL changes (the LB is reassigned, the datastore failed over to a replica, a blue/green flip happened), ZopDay re-renders the consumer’s deployment with the new value.
The re-render is automatic for changes ZopDay observes (cloud-side updates, ZopDay-triggered LB swaps). For changes ZopDay can’t observe, the connection re-resolves on the next deploy of the consumer.
What counts as a “target connection URL”
Depends on the target type:
| Target | Connection URL source |
|---|---|
| Deployment with a Kubernetes Service | The Service’s cluster-internal DNS + port; <svc>.<ns>.svc.cluster.local:<port> |
| Deployment with a load balancer (cloud LB or Ingress) | The LB’s external hostname or the Ingress’s external IP, depending on which one is the canonical entry point |
| Datastore (RDS / Cloud SQL / Azure DB) | The cloud-side endpoint + port, plus credentials from the cloud secret manager (ZopDay does not put the password in the env var directly; it puts a reference to the secret manager path so the consumer pulls it at runtime via IRSA / workload identity / managed identity) |
| Cache (ElastiCache / Memorystore / Azure Cache for Redis) | Same as datastore |
For datastores and caches, the injected env var is a reference to a secret manager path, not the password itself. The consumer’s pod reads the actual secret at runtime using whichever identity is bound to its service account. This avoids ever putting datastore passwords in plain env vars.
Endpoint surface
CRUD lives at:
GET /orgs/{orgID}/environments/{envID}/deployments/connectionsPOST /orgs/{orgID}/environments/{envID}/deployments/connectionsGET /orgs/{orgID}/environments/{envID}/deployments/connections/{connectionID}PATCH /orgs/{orgID}/environments/{envID}/deployments/connections/{connectionID}DELETE /orgs/{orgID}/environments/{envID}/deployments/connections/{connectionID}PATCH lets you change injectedVar (rename the env var) or null it out (downgrade to visualisation-only) without dropping and re-creating the connection; the edge on the canvas stays in place.
How connections render on the canvas
The architecture canvas (Topology view) joins the project → env → deployment tree from the config service with the service_connections rows from the deployer service:
- Each deployment is a node
- Each connection is an edge from
sourcetotarget - Connections with
injectedVarset show the env var name on the edge label - Hovering an edge shows the resolved connection URL and the last refresh time
The canvas is served by joining the catalog tree with the service connections at render time.
What connections do NOT do
A few common misconceptions:
- They don’t establish network paths. Network reachability is a separate concern. Kubernetes Network Policies, VPC peering, security groups, etc. A connection on the canvas does not magically open a port.
- They don’t act as service discovery for the consumer. The injected env var IS the service discovery. Your code reads
os.environ["REDIS_URL"], not a ZopDay client. - They don’t enforce ordering at deploy time. Connections are descriptive, not prescriptive. If you need the target to be up before the source can start, encode that in your container’s startup logic (readiness probe waiting for the target’s
/healthz) rather than expecting ZopDay to sequence the deploys.
When to delete a connection
When the consumer no longer reads from the target; for example, you migrated REDIS_URL to point at a managed Redis service outside ZopDay. Deleting the connection removes the env var injection from the consumer on the next deploy.
If you want the env var to keep its current value but stop being managed by ZopDay, downgrade the connection to visualisation-only by PATCHing injectedVar to null. The env var stays on the consumer’s last deploy, but ZopDay won’t refresh it.