How Cloud Development Environments Work
The path from a request to a running workspace: control plane, templates, provisioning, the connection layer, lifecycle, and where your state actually lives.
The Shape of the System
Every CDE platform, self-hosted or managed, is the same three pieces: a control plane that decides things, a compute substrate where workspaces actually run, and a connection layer that gets a developer's editor to the workspace. The editor stays local. The file system, the compiler, the tests, and the running application do not.
The five steps below trace one request through that system. The environment definition each step consumes is the subject of the core concept; this page is about what happens to it.
The Control Plane Holds Everything Together
The control plane is the small always-on service that makes a collection of virtual machines into a platform. It is deliberately not in the data path: developer keystrokes and file contents flow directly between the client and the workspace, so the control plane can be restarted for an upgrade without disconnecting anyone who is mid-edit. That separation is worth understanding, because it determines what actually breaks when the control plane is unavailable - you usually cannot start or stop a workspace, but existing sessions keep working.
Federates to the corporate identity provider by OIDC or SAML, maps groups to roles, and decides which templates a person may use and which resource tiers they may request.
Stores published template versions, tracks which workspaces run which version, and lets a platform team roll a change forward or back without touching individual workspaces.
Runs the provisioner that turns a template into real resources, holds the resulting state, and reconciles the desired workspace state (running, stopped, deleted) against reality.
Enforces idle timeouts, maximum lifetimes, per-user and per-team resource caps, and writes the audit log of who created, connected to, and destroyed what.
Where the control plane lives is the main deployment decision. Self-hosted platforms put it inside your network, so nothing about your workspaces is visible to a vendor. Managed platforms run it as a service, which removes the operational burden and adds a dependency. A middle pattern - a vendor-operated control plane driving runners inside your own cloud account - keeps workspace data in your VPC while the coordination stays hosted. See reference architectures.
Templates Define the Workspace, Parameters Vary It
A template is the environment definition plus the infrastructure it needs, published to the control plane by a platform team. Parameters are the small set of choices left open to the requester. Getting the split right is most of the design work: too few parameters and every team forks the template; too many and you have rebuilt the ad-hoc laptop, only slower.
Base image, security agents, network policy, identity the workspace assumes, audit hooks. These are the things a platform team is accountable for and must not be overridable.
Repository and branch, resource tier, region, idle timeout, optional extras such as a GPU or a second database. Usually a short validated list rather than free text.
Templates are versioned like any other code. Publishing a new version does not rewrite running workspaces; it marks them as outdated so their owners can rebuild at a moment that suits them, which is how a runtime upgrade rolls out without a coordinated stop-the-world event. A workspace built from an older template version keeps working until it is rebuilt.
# A Coder template, trimmed: infrastructure plus an agent
resource "coder_parameter" "cpu" {
name = "cpu"
display_name = "CPU cores"
type = "number"
default = 4
validation { min = 2, max = 16 }
}
resource "coder_agent" "main" {
os = "linux"
arch = "amd64"
startup_script_behavior = "blocking"
}
resource "kubernetes_pod" "workspace" {
spec {
container {
image = "ghcr.io/org/base@sha256:9f2c..."
resources {
requests = { cpu = data.coder_parameter.cpu.value }
limits = { memory = "16Gi" }
}
}
}
}Note the digest-pinned image and the validated numeric parameter. Both are what stop a template from quietly producing a different environment next month.
Provisioning: Turning a Template Into Running Compute
The control plane hands the template and the chosen parameters to a provisioner, which creates the real resources and records what it created. The substrate underneath is a genuine trade-off rather than a detail: containers start fastest and pack densest, full VMs give the strongest isolation and can run nested virtualization, and microVMs sit between the two.
Once compute exists, an agent process starts inside the workspace and registers back to the control plane. That agent is what runs the lifecycle scripts, reports health and resource usage, forwards ports, and terminates the connection tunnels. A workspace that provisions successfully but never shows as ready is almost always an agent that could not reach the control plane - a network policy or egress problem, not a template problem.
Cold start is the number people feel. The naive path - pull image, clone repository, install dependencies, build - can take many minutes. Platforms attack it in three places: prebuilding warm workspaces from the current default branch so one is already waiting, snapshotting the post-install volume so dependency installation is skipped, and keeping a pool of pre-warmed compute so scheduling is not on the critical path. If startup time is your adoption blocker, one of those three is the fix, and none of them are automatic.
The Connection Layer
Every connection method is a remote development protocol carrying a split application: a thin piece rendering locally and a heavy piece running in the workspace. What differs is where the split falls, which is what determines how the connection feels on a poor network. Editors that send keystrokes and receive text diffs stay usable at high latency; anything that round-trips per keypress does not.
VS Code Remote SSH
Local VS Code connects over SSH and installs a server component in the workspace. Extensions, language servers, search, and the terminal all execute remotely; only the UI is local. ProxyCommand support lets a platform inject its own authentication and routing without the developer editing an SSH config by hand.
JetBrains Gateway
A thin local client attaches to a full JetBrains IDE backend running in the workspace - IntelliJ IDEA, PyCharm, WebStorm, GoLand and the rest. Indexing happens remotely, which is the point for large codebases, since the index is rebuilt on infrastructure rather than on a laptop fan.
Browser-Based IDE
An editor served from the workspace itself over a WebSocket, usually code-server or OpenVSCode Server. Nothing is installed locally, which makes it the right answer for contractors, unmanaged devices, and the first ten minutes of onboarding. Marketplace availability and some native integrations differ from desktop VS Code.
Plain SSH
A shell, for terminal-first workflows, Vim and Emacs users, scripting, and any headless process. Most platforms front this with their own SSH gateway issuing short-lived certificates, so there are no long-lived keys to distribute or revoke per workspace.
Relayed Tunnels
The workspace dials out to a relay and the client meets it there, so no inbound port is opened and no direct route is needed. This is what makes CDEs work behind restrictive corporate egress rules, at the cost of trusting the relay operator with connection brokering.
Port forwarding sits alongside all of these: the agent tunnels a port from the workspace back to localhost on the developer's machine, so an application running remotely is reachable at a local address in a normal browser. Whether those forwarded ports are private to the developer or shareable by URL is a policy setting worth checking before rollout. Protocol details are covered in remote dev protocols.
Lifecycle and Where State Lives
A workspace is not just on or off, and the states in between are where both the cost savings and the surprises come from. The distinction that matters is what each transition preserves.
| Transition | What happens | What survives | Still billing? |
|---|---|---|---|
| Start | Compute allocated, volume attached, agent registers, startup scripts run | n/a | Compute and storage |
| Stop | Processes killed, compute released, persistent volume retained | Files on the persistent volume only | Storage only |
| Hibernate | Memory image written to disk, compute released | Files plus running processes and shell history | Storage, including the memory image |
| Rebuild | Workspace recreated from the current template version | Persistent volume, if the template mounts one | Compute and storage |
| Destroy | All resources including volumes deleted | Nothing - only what was pushed to Git | No |
Where state actually lives
Most support tickets in a CDE rollout are really questions about this. A typical workspace has three storage tiers with three different guarantees, and the mental model people bring from laptops - "everything I saved is still there" - is wrong for two of them.
Persistent volume
Usually the home directory and the working copy. Survives stop and, if configured, rebuild. This is the only tier a developer should treat as durable, and even then it is not a backup.
Container filesystem
Everything outside the mounted volume - system packages installed by hand, files written to /tmp or /opt. Discarded on rebuild. If it needs to survive, it belongs in the template.
External services
Git remotes, artifact registries, secrets managers, shared databases. Independent of workspace lifetime, which is exactly why the correct habit is to push work before stopping.
Personal configuration is handled separately, normally by a dotfiles repository the platform clones on start. That keeps individual preferences out of the shared template while still letting every rebuilt workspace come back with the right shell, aliases, and editor settings. Idle timeouts and maximum lifetimes are the other half of this picture: they are what stops forgotten workspaces from becoming a permanent line on the cloud bill, and they are covered in cost analysis.
The Same Path, Without a Human
Nothing above requires a person clicking a button. The dashboard is one client of the control plane API, and CI pipelines, internal developer portals, and AI coding agents are others. A programmatic caller creates a workspace from a template, supplies parameters, waits for the agent to report ready, connects over SSH, and destroys the workspace when the job is done - the identical five steps, driven by a token instead of a login session.
# Create a short-lived workspace from a template
curl -X POST https://coder.example.com/api/v2/workspaces \
-H "Authorization: Bearer $TOKEN" \
-d '{
"template_id": "ephemeral-build",
"name": "task-4821",
"ttl_ms": 14400000,
"rich_parameter_values": [
{ "name": "repo", "value": "github.com/org/backend" },
{ "name": "branch", "value": "feature/auth-refactor" }
]
}'Two mechanics matter more in this mode than in the interactive one. A time-to-live is mandatory, because an automated caller that fails halfway leaves a running workspace behind and nobody notices. And the token needs its own identity with its own scopes, so that a workspace created by automation cannot reach further than the job requires. The wider design of agent-driven workflows is covered in agentic AI and CDEs, with the isolation side in sandbox environments.
Connection Protocols Compared
Latency figures below are practical comfort thresholds reported by users of each client, not vendor specifications. Treat them as a planning guide for how far a workspace can sit from the people using it.
| Protocol | Used by | Comfortable RTT | Best for |
|---|---|---|---|
| SSH | VS Code Remote, terminal, automation | Under 100ms | Universal access, scripting |
| WebSocket | Browser IDEs, code-server | Under 150ms | Zero-install access |
| JetBrains client protocol | JetBrains Gateway | Under 200ms | Full IDE on large codebases |
| Relayed tunnel | Clients behind restrictive egress | Under 200ms | No inbound ports available |
| RDP or VNC | Windows desktops, GUI applications | Under 50ms | Visual and GUI testing |
Automation collapses to SSH. When a pipeline or an agent connects to a workspace it uses SSH, or a CLI that wraps SSH. There is no interface to render - it needs a shell, a filesystem, and an exit code. That is why SSH remains the load-bearing protocol underneath every CDE, however the human-facing clients evolve.
How Real Platforms Map to This Model
The same five steps, arranged differently. What varies between products is who operates the control plane and how much of the template you write yourself. Full comparison on the tools page.
Coder
You operate the control plane. Templates are Terraform, so the provisioner is Terraform and the substrate is whatever your providers can reach - Kubernetes, EC2, bare metal, air-gapped. Two editions: Community, which is free, open source and self-hosted, and Premium, whose price is not published.
Ona (formerly Gitpod)
The control plane is operated by the vendor. Workspaces can run on runners placed in your own AWS or GCP VPC on the Enterprise tier, so workspace data stays in your account - but there is no customer-managed self-hosted option. OpenAI announced an agreement to acquire Ona on 06-11-2026; the deal has not closed.
GitHub Codespaces
Fully managed. The template is a devcontainer.json in the repository, so there is no separate template layer to maintain. Prebuilds are driven by GitHub Actions. Included usage on GitHub Free is 120 core-hours and 15 GB-month per month, and 180 core-hours and 20 GB-month on Pro - core-hours, not wall-clock hours, so a 4-core machine consumes the allowance four times as fast.
DevPod
There is no control plane. A client on the developer's machine reads a devcontainer.json and drives a provider - local Docker, Kubernetes, or a cloud VM - directly. That removes the operational burden and the central governance along with it, which makes it a good fit for individuals and small teams and a poor one for policy enforcement.
Okteto and Eclipse Che
Both are genuinely self-hostable and open source, and both put the control plane in a Kubernetes cluster you already run. Worth naming explicitly because fully customer-operated options have become scarce as the market has consolidated around managed services.
Microsoft Dev Box
Azure-managed Windows VMs rather than containers, so the substrate is a full desktop and the connection is RDP. The natural choice for .NET, Visual Studio, and anything needing a Windows GUI, and it inherits Intune and Entra policy rather than defining its own.
Two names to strike from shortlists. Daytona is no longer a CDE: it pivoted to AI agent sandbox infrastructure, and its public repository became unmaintained in June 2026 when core development moved to a private codebase. AWS Cloud9 closed to new customers on 07-25-2024 and is in maintenance mode, though no end-of-life date has been announced.
