Projects and environments
How ZopDay organises deployments into projects and environments; the catalog hierarchy that drives everything else.
ZopDay’s deployment catalog is a three-level hierarchy: Project → Environment → Deployment. Get this right at the start and the rest of the product slots in around it cleanly. Get it wrong and you’ll be reshuffling for weeks.

The Projects list; each project with its environments and health, the top of the Project → Environment → Deployment hierarchy.
The hierarchy
Organisation └── Project (org-scoped grouping; usually a service, team, or app) └── Environment (binds to a space + namespace + registry) └── Deployment (a git repo + branch + config) └── Revision (one rollout; built image + Helm release)| Level | Owned by | Stored as | What it represents |
|---|---|---|---|
| Project | Org | Catalog | An org-scoped grouping. Org name + project name is unique. |
| Environment | Project | Catalog | The “where”; a space + namespace + (optional) registry integration. |
| Deployment | Environment | Catalog | The “what”; repo URL, branch, config. Infra fields are inherited from the parent environment. |
| Revision | Deployment | Runtime | One rollout. Carries the built image and its rollout state. |
The split between catalog and runtime data is deliberate; see the deployments concept page for why.
Projects
A project is the top-level grouping. Org-scoped, soft-deletable, no nesting.
When to create a project
- One service that has its own repo, owners, and release cadence → one project
- A monorepo with multiple deployable services → still one project; multiple deployments inside it
- A platform team’s shared infrastructure (gateways, ingress controllers, observability stack) → its own project, separate from product projects
Project fields
| Field | Required | Notes |
|---|---|---|
name | yes | Org-unique. Used in URLs and as a label. Lowercase kebab-case recommended. |
description | no | Free-form. Shows on the project list. |
canvasPosition | no | {x, y} finite numbers. Drives layout on the architecture canvas. |
Project endpoints
POST /projects CreateGET /projects List with filtersGET /projects/{id} Get onePATCH /projects/{id} Partial updateDELETE /projects/{id} Soft-deleteGET /projects/{id}/stats Per-project deployment / revision countsEnvironments
An environment binds a project to a runnable target. Every deployment lives inside exactly one environment, and the environment provides the infrastructure context.
Environment fields
| Field | Required | Notes |
|---|---|---|
name | yes | Project-unique. Common patterns: prod, staging, qa, dev, or preview-{slug}. |
space_id | yes | The registered Kubernetes cluster. See Cluster registration. |
namespace | yes | The Kubernetes namespace inside the space. ZopDay creates it if it doesn’t exist (with the right RBAC). |
registry_integration_id | no | Where built images are pushed. If unset, ZopDay uses the cloud-default registry (ECR / Artifact Registry / ACR) on the same cloud account as the space. |
Why bind the namespace at the environment level
Because deploys cross-reference each other by environment. If two deployments live in payments-prod (same environment), they can wire up via service connections without specifying a namespace explicitly; the platform knows where to look.
Multiple environments can share a namespace if you really need to (e.g. a staging environment that lives in the same namespace as another project’s staging) but it’s discouraged; you give up isolation guarantees on resource limits, RBAC, and tear-down.
Environment endpoints
POST /projects/{projectID}/environments CreateGET /projects/{projectID}/environments ListGET /environments/{envID} Flat get (no project context needed)PATCH /projects/{projectID}/environments/{id} Partial updateDELETE /projects/{projectID}/environments/{id} Delete
GET /environments/{envID}/deployments List deployments in this envPOST /environments/{envID}/deployments Create deployment in this envGET /environments/{envID}/stats Per-env deployment / revision countsNamespace discovery on the cluster behind an environment is served at GET /space-discovery/{spaceID}/namespaces (it needs a kubeconfig); see Deployment spaces and the API reference for request/response details.
Common patterns
One project per service, multiple environments
The most common shape. Each service is a project; each project has dev, staging, prod environments, each bound to a different cluster (or the same cluster, different namespaces).
payments (project) ├── dev → space: shared-dev-cluster, namespace: payments-dev ├── staging → space: staging-cluster, namespace: payments-staging └── prod → space: prod-cluster, namespace: payments-prodOne project, many ephemeral environments (preview branches)
Each PR gets its own short-lived environment. Common pattern for review apps.
payments (project) ├── prod → space: prod, namespace: payments-prod ├── staging → space: staging, namespace: payments-staging ├── preview-pr-1234 → space: review, namespace: pr-1234 (auto-created on PR open) ├── preview-pr-1245 → space: review, namespace: pr-1245 └── ...The preview environments are torn down by automation on PR close; call DELETE /environments/{id} from your CI on the close webhook. Cascading deletion removes the deployment rows and any pending revisions.
Multi-tenant platform team
A platform team running shared services (ingress controllers, observability) keeps them in their own project, bound to a different namespace per cluster.
platform (project) ├── prod → space: prod, namespace: platform-system └── dev → space: dev, namespace: platform-systemWhat changes when you change an environment
Two infra fields on the environment can change in place:
| Change | What happens |
|---|---|
namespace | Existing deployments do not migrate. ZopDay flags a divergence; you can re-deploy each one to land it in the new namespace. |
registry_integration_id | New builds push to the new registry. Existing revisions still reference their original image hashes. Re-deploy to pin everything to the new registry. |
space_id | Same as namespace; flagged but not auto-migrated. Use carefully. |
A space_id change is usually a “we’re moving from cluster A to cluster B” event. Coordinate with whoever owns DNS and load balancing on top.
Org cascade
Deleting an organisation cascades, which:
- Soft-deletes every project owned by the org
- Soft-deletes every environment inside those projects
- Soft-deletes every deployment + revision inside those environments
- Wipes org settings (including default dashboards, default cluster, etc.)
Spaces are not deregistered on org deletion; the underlying cluster is yours, not ZopDay’s. If you also want to remove the cluster-side artefacts, run a teardown per deployment before the org cascade.