Ship a Reproducible Dev Environment with VS Code Dev Containers
Set up a Docker-backed .devcontainer folder so every team member gets the same Node version, extensions, and system packages the moment they open the project.
What You'll Build
You'll add a .devcontainer folder to an existing project and configure a Docker-backed development environment that VS Code (and GitHub Codespaces) can start with a single command. Anyone who clones the repo gets the same Node version, system packages, and editor extensions without touching their local machine.
Prerequisites
- VS Code 1.74 or later with the Dev Containers extension (
ms-vscode-remote.remote-containers) installed - Docker Desktop 4.x on macOS or Windows, or Docker Engine 20.10+ on Linux. Apple Silicon users: Docker Desktop handles ARM64 natively; prefer ARM-native images where available.
- A project folder with a
package.json(this tutorial uses Node 20; the pattern works for any runtime) - Comfortable with basic Docker concepts: images, containers, layers
1. Create the .devcontainer Folder
At your project root:
mkdir .devcontainer
Everything VS Code needs lives here. The only required file is devcontainer.json.
2. Write devcontainer.json
Create .devcontainer/devcontainer.json:
{
"name": "Node.js 20",
"image": "mcr.microsoft.com/devcontainers/node:1-20-bookworm",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
},
"forwardPorts": [3000],
"postCreateCommand": "npm install",
"remoteUser": "node"
}
| Field | What it does |
|---|---|
image |
Pre-built base image from Microsoft's devcontainers registry |
features |
Installs extra tools without a custom Dockerfile |
customizations.vscode.extensions |
Extensions auto-installed inside the container |
forwardPorts |
Maps container port 3000 to your localhost |
postCreateCommand |
Runs once after the container starts (installs deps here) |
remoteUser |
Non-root user VS Code connects as (node is built into this image) |
3. Add a Custom Dockerfile When You Need More Control
The image field covers most cases. When you need specific system packages, swap it for a build block pointing at a custom Dockerfile.
Create .devcontainer/Dockerfile:
FROM mcr.microsoft.com/devcontainers/node:1-20-bookworm
RUN apt-get update && apt-get install -y --no-install-recommends \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
Then replace the entire contents of .devcontainer/devcontainer.json with the file below. The only change from Step 2 is that "image" is removed and a "build" block takes its place; all other fields are preserved:
{
"name": "Node.js 20",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
},
"forwardPorts": [3000],
"postCreateCommand": "npm install",
"remoteUser": "node"
}
Setting "context": ".." points Docker at the project root (one level up from .devcontainer/), which is needed if your Dockerfile ever copies project files during the build.
4. Open the Folder in the Container
With Docker running, open the Command Palette (Cmd+Shift+P on macOS, Ctrl+Shift+P on Windows/Linux).
If the project is already open in VS Code (the common case), run:
Dev Containers: Reopen in Container
If you haven't opened the folder yet, use:
Dev Containers: Open Folder in Container
VS Code will pull the base image (cached after the first run), apply features, mount your project at /workspaces/<project-name>, install the listed extensions inside the container, and run postCreateCommand. The status bar at the bottom-left turns blue and shows the container name when you're connected.
After editing devcontainer.json, apply changes with:
Dev Containers: Rebuild Container
5. Verify It Works
Open the integrated terminal (Ctrl+`). You're now inside the container:
node --version
# v20.x.x
gh --version
# gh version 2.x.x
whoami
# node
Project files are live-mounted, so edits in VS Code sync instantly without a rebuild. Start your app:
npm run dev
VS Code auto-forwards port 3000. Open http://localhost:3000 in your host browser.
Using with GitHub Codespaces
Push .devcontainer/ to your repo. On GitHub, click Code > Codespaces > Create codespace on main. GitHub spins up the identical environment in the cloud with no local Docker required. The spec is the same file; nothing extra to configure.
Troubleshooting
"Cannot connect to the Docker daemon"
Docker Desktop isn't running. On Linux, your user may not be in the docker group. Fix it with sudo usermod -aG docker $USER, then log out and back in.
Extension won't install inside the container Some extensions are marked local-only by their publishers and can't run remotely. Check the extension's marketplace page under the "Remote" section for compatibility. You can still install those extensions on your local VS Code instance; they'll apply to the host UI.
Port isn't reachable on the host
Confirm forwardPorts is set and you've rebuilt after changing it. As a fallback, open the Ports panel (View > Open View > Ports) and forward the port manually from there.
Image pull fails on Apple Silicon
Some older images lack a linux/arm64 manifest. Add "runArgs": ["--platform=linux/amd64"] to devcontainer.json to force x86 emulation via Rosetta, or find an ARM-native alternative image.
Next Steps
- Add a database service by switching to Docker Compose: replace
imagewithdockerComposeFileandserviceindevcontainer.json. The official Compose-based dev containers guide walks through the full setup. - Browse available Features at containers.dev/features; Python, Go, Rust, AWS CLI, and dozens more are ready to drop in.
- Pin feature versions for team stability:
"ghcr.io/devcontainers/features/github-cli:1.0.5": {}prevents unexpected updates from breaking your environment. - Sync your dotfiles automatically by setting
Dev > Containers: Dotfiles Repositoryin VS Code settings. Dev Containers will clone and run your dotfiles installer in every new container.
Priya covers AI frameworks, developer productivity tooling, and the startup ecosystem across South and Southeast Asia, bringing a researcher's rigour and a practitioner's empathy to every story. She is deeply sceptical of benchmarks and asks hard questions so her readers don't have to.
Discussion 0
No comments yet
Be the first to weigh in.