Environments
Environments are isolated deployment targets. Each one gets its own Kubernetes namespace, its own configuration overrides, and its own sync status.
Use environments
When you create a project, Lucity automatically creates a development environment. Additional environments are created on-demand when you need them.
The typical setup:
- Development: where you iterate fast and break things freely. Created automatically with your project.
- Staging: where you validate before production. Same config, lower resource limits. Created when you're ready for a promotion pipeline.
- Production: where your users live. Higher replicas, tighter resource constraints, the careful deployment.
These aren't hardcoded; you can name them whatever makes sense for your team. But development-staging-production is the well-trodden path for a reason.
Create additional environments
You can create environments for any purpose: staging, production, feature testing, load testing:
Ephemeral environments carry a lucity.dev/ephemeral: "true" label so you can tell them apart from permanent ones.
mutation {
createEnvironment(input: {
projectId: "myapp"
name: "staging"
}) {
id
name
namespace
}
}
Optionally clone from an existing environment's configuration to start with known-good settings instead of defaults.
Switch environments
The dashboard's environment switcher lets you jump between deployment targets with a click. Every view (services, deployments, logs) updates to reflect the selected environment. It's the fastest way to compare what's running where.
Monitor environment sync status
Each environment reports its sync state, telling you whether the latest GitOps changes have been applied to Kubernetes:
| Status | Meaning |
|---|---|
SYNCED | Everything is up to date. Relax. |
OUT_OF_SYNC | Changes in the GitOps repo haven't been applied yet. |
PROGRESSING | ArgoCD is actively applying changes. |
DEGRADED | Something went wrong during sync. Time to investigate. |
UNKNOWN | Can't determine the status. Usually transient. |
You'll see these in the dashboard and through the API on every environment query. No guessing, no "did my deploy go through?" anxiety.
See how it maps to Kubernetes
Each environment is a Kubernetes namespace with standard labels:
apiVersion: v1
kind: Namespace
metadata:
name: myapp-production
labels:
lucity.dev/project: "myapp"
lucity.dev/environment: "production"
Ephemeral environments add one more label:
labels:
lucity.dev/project: "myapp"
lucity.dev/environment: "pr-142"
lucity.dev/ephemeral: "true"
Standard kubectl queries work perfectly. No custom CRDs, no proprietary resources.
Choose a resource tier
Each environment runs on a resource tier that determines pricing and performance characteristics:
- ECO: shared resources at lower cost. Good for development, staging, and non-critical workloads.
- PRODUCTION: dedicated resources with higher performance guarantees. Designed for production traffic and workloads that need consistent performance.
Set the resource tier when creating an environment or update it later. The tier affects the per-unit pricing for CPU, memory, and disk in that environment.
Understand the GitOps structure
Environment configuration follows a layered approach in the GitOps repository:
gitops/myapp/
├── base/
│ ├── Chart.yaml # Depends on lucity-app chart
│ └── values.yaml # Shared config: services, databases, base settings
└── environments/
├── development/
│ └── values.yaml # Overrides: image tag, debug settings
├── staging/
│ └── values.yaml # Overrides: promoted image tag
└── production/
└── values.yaml # Overrides: replicas, resources, HA config
The base/ directory holds configuration shared across all environments: service definitions, database settings, common config. Each environment directory contains a values.yaml that overrides specific values: image tags, replica counts, resource limits, feature flags.
This means you define your service once in base/ and customize per-environment without duplicating everything. Helm's value merging handles the rest.