GitHub Codespaces: Dev Environments as Configuration
Your dev environment belongs in version control. A devcontainer.json plus GitHub Codespaces reproduces the exact setup on any machine in minutes.
Netbay Cloud Team
Netbay Engineering
On this page
"Works on my machine" is a versioning problem dressed as a personality flaw. The fix is to make the machine a file: devcontainer.json declares your environment — image, tools, scripts, ports, extensions — in a single JSON document, and GitHub Codespaces is one well-tested runner for that same standard. The same file drives a local container on your laptop and a cloud workspace for a new teammate, so there is no separate "setup" to drift.
The devcontainer contract
A devcontainer.json at the repository root describes how to build the container the project expects:
{
"name": "netbay-api-dev",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"postCreateCommand": "npm ci",
"forwardPorts": [3000],
"portsAttributes": {
"3000": { "label": "app" }
},
"customizations": {
"vscode": {
"extensions": ["esbenp.prettier-vscode"],
"settings": { "editor.formatOnSave": true }
}
},
"remoteUser": "node"
}Read it as a contract: "image" is the base toolchain, "features" bolt on extras without hand-writing a Dockerfile, "postCreateCommand" runs once when the workspace is first created, "forwardPorts" and "portsAttributes" publish what a dev needs, and "customizations" carry editor settings and extensions so a new hire inherits your formatting rules without a setup ritual.
Lifecycle hooks: the order that matters
The container lifecycle has three hooks and getting the order right matters:
- **postCreateCommand** runs after the container is created, on a fresh clone — this is where the full "npm ci" and migrations live.
- **postStartCommand** runs every time the container starts, on the cheap operations.
- **postAttachCommand** runs when an editor or terminal attaches — print a banner, keybindings recovery, nothing expensive.
A common mistake is putting a ten-minute build in postStart and then wondering why every restart is slow. Post-Create is the expensive one; post-Start should be able to finish in seconds.
Features and dotfiles
Devcontainer features are composable bundles — docker-in-docker, protoc, a specific Node runtime — pulled from a registry when the container is built. Beyond the container itself, a dotfiles repository supplies shell configuration, so the terminal feels like home no matter which fresh container file created it. Together they are the difference between "here is a container" and "here is the developer experience." Features are versioned by their registry reference, so the same devcontainer.json resolves to the same toolchain next month; that reproducibility is the entire point, and it is why the file belongs in the same review as the code it supports rather than in a private gist nobody updates.
Test it before the cloud
Codespaces is optional; the devcontainer standard is not locked to it. You can preflight the same file on any Docker-capable host using the devcontainer CLI, which is exactly what CI or a stubborn laptop should do:
# build the workspace, run a command inside it, then tear down
npx --yes @devcontainers/cli up --workspace-folder .
npx --yes @devcontainers/cli exec --workspace-folder . pnpm testIf the command works in a plain container on your own machine, it will work in the cloud workspace — same file, same result. For teams whose builds outgrow laptop batteries altogether, the same devcontainer image runs happily on a Linux VPS, where the heavy compiles happen at always-on speed while you edit over SSH.
When Codespaces is the right call
Reach for cloud dev environments when onboarding matters more than anything — every new hire starts from the same file within minutes — when the local machine cannot hold the build, and when a clean-room workspace for risky dependency experiments beats wiping your own laptop. Keep the cost question honest: session time adds up, so pair heavy paid machines with cheap, correct defaults rather than defaulting to the biggest option. And keep the file boring: the base image, one or two features, hooks that finish fast. One caveat: a cloud workspace inherits the same access controls as your account, so treat it as a boundary, not a security wall — secrets belong in the environment at runtime, never baked into the image or the dotfiles repository.
Takeaway: devcontainer.json turns your environment into a reviewed, versioned artifact, and Codespaces is just its most convenient runner. The same standard runs in a container on your machine or on a Linux box you control — like a Lucknow DC01 VPS from Netbay, ready in under 60 seconds at netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance