Eliminating 'Works on My Machine' with devcontainer.json
Stop wasting onboarding time on local setup. Learn how to use devcontainer.json in GitHub Codespaces to standardize runtimes, tools, and editor extensions for your entire team.
03 Dec 2025, 12:32 UTC

The Onboarding Friction Problem
New engineers often spend their first two days fighting with local environment setups. A missing system library, an incompatible Node.js version, or a forgotten VS Code extension can stall a project before a single line of code is written. Even with a detailed README, manual setup is prone to human error.
The solution is to shift the environment definition from a document to a configuration file. By using devcontainer.json in GitHub Codespaces, you define the exact runtime, tools, and editor settings as code, ensuring every team member launches an identical environment in seconds.
Defining the Runtime and Tooling
The devcontainer.json file lives in the .devcontainer/ directory of your repository. It acts as the blueprint for the container GitHub spins up. Instead of writing complex Dockerfiles for every small tool, you can use Features—pre-packaged installation scripts maintained by the community or GitHub.
Features allow you to layer capabilities like the AWS CLI, Terraform, or Docker-in-Docker onto a base image without managing the underlying shell scripts. This keeps your configuration declarative and easier to audit.
Automating the 'Ready-to-Code' State
A container with the right OS is only half the battle; you also need the project dependencies installed. The postCreateCommand property allows you to run scripts immediately after the container is created. This is where you handle npm install, pip install, or database migrations.
To ensure the editor is also standardized, the customizations block allows you to specify a list of VS Code extensions. This forces a shared standard for linting and formatting, preventing "noise" in pull requests caused by different developers using different editor settings.
Worked Example: A Full-Stack Node.js Setup
Below is a configuration for a Node.js project that requires the GitHub CLI, a specific set of extensions, and automatic dependency installation. Place this in .devcontainer/devcontainer.json.
{
"name": "Node.js Full-Stack Env",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-azuretools.vscode-docker"
]
}
},
"forwardPorts": [3000],
"postCreateCommand": "npm install"
}Implementation Details
- Run Location: This file is interpreted by the GitHub Codespaces backend during the build phase. No manual command is needed to trigger it; it runs upon creating the Codespace.
- Permissions: The
postCreateCommandruns as the default user defined in the image (usuallyvscode). - Expected Result: Upon launch, the terminal should show the completion of
npm install, and the 'Ports' tab in VS Code should automatically list port 3000 as forwarded. - Risk: If
npm installfails due to a network issue or package conflict, the container will still start, but the environment will be incomplete. Check the 'Create Codespace' logs to verify success.
Trade-offs and Performance Constraints
While automating everything is tempting, there is a performance cost. Heavy postCreateCommand scripts increase the time it takes for a developer to reach a usable prompt. If your dependency installation takes several minutes, consider building a custom Docker image with those dependencies pre-baked and referencing that image in the image property instead. Note that large custom Dockerfiles can also slow builds if layers are not ordered to take advantage of caching.
Additionally, avoid placing secrets (like API keys) directly in the devcontainer.json. Use GitHub Codespaces Secrets in your repository or organization settings to inject environment variables securely into the container at runtime.
Verifying Your Environment
To confirm the configuration is working as intended, perform these three checks after launching your Codespace:
- Tool Check: Run
gh --versionin the terminal to verify the GitHub CLI feature was installed. - Extension Check: Open the Extensions view (Ctrl+Shift+X) to ensure ESLint and Prettier are active.
- Network Check: Start your application on port 3000 and click the notification popup to open the forwarded URL in your browser.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.