Using VS Code Remote - Containers to Eliminate 'Works on My Machine'
Learn how VS Code Remote - Containers lets you lock down a development environment with devcontainer.json, eliminating 'works on my machine' issues.
16 Jan 2026, 11:41 UTC

The problem: inconsistent environments
When developers switch laptops, CI agents, or pair with teammates, small differences in installed runtimes, extensions, or OS patches often cause the dreaded "works on my machine" syndrome. Debugging these mismatches wastes time and erodes confidence in the build.
Solution: define a dev container
VS Code's Remote - Containers extension lets you commit a devcontainer.json (and optional Dockerfile) to your repository. Everyone who opens the folder in a container gets the same isolated environment with identical tools, runtimes, and extensions.
Install the extension
Open the Extensions view (Ctrl+Shift+X) and search for "Remote - Containers". Install it; no admin rights are required beyond the ability to run Docker on the host.
Add devcontainer.json
Create a .devcontainer folder at the root of the repo and place a devcontainer.json file inside. The following example configures a Node.js 20 environment with Yarn and the ESLint extension:
{
"name": "Node.js 20",
"dockerFile": "Dockerfile",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"extensions": [
"dbaeumer.vscode-eslint"
],
"forwardPorts": [3000],
"postCreateCommand": "yarn install"
}
If you prefer a Dockerfile, a minimal one could be:
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-20
RUN corepack enable && corepack prepare yarn@stable --activate
Workflow inside the container
Once the container is running, editing, debugging, and terminal work behave as they do locally. The extension mounts the workspace, forwards declared ports, and syncs Git credentials so breakpoints, linting, and IntelliSense remain functional.
Editing, debugging, terminal
Open any source file; IntelliSense reflects the modules installed in the container. Set a breakpoint in the Debug view and press F5 – the debugger attaches to the process inside the container. The integrated terminal shows the container's shell, where you can run node -v or yarn --version to confirm the expected versions.
Worked example: Node.js project
Consider a repo with a simple Express app in src/index.js that listens on port 3000. After adding the devcontainer.json above:
- Open the command palette (Ctrl+Shift+P) and run "Remote-Containers: Open Folder in Container".
- Wait for the build to complete (first run may take several minutes depending on the base image and network).
- In the bottom‑left status bar, you should see "Dev Container: Node.js 20".
- Open a terminal (Ctrl+`) and run
node -v. The output should bev20.x.x. - Run
yarn dev(ornpm startif you prefer npm). The app starts and is accessible athttp://localhost:3000. - Set a breakpoint in
src/index.jsand refresh the browser; the debugger should pause as expected.
Trade‑off and limitation
The primary trade‑off is startup time: building the container the first time can take several minutes, and large base images increase disk usage and network bandwidth. Performance‑intensive GUI tools (e.g., heavyweight designers) may feel slower inside the container because graphics are forwarded over the network. Additionally, extensions that rely on host‑specific binaries (such as certain database clients) need those binaries included in the Dockerfile or remapped via mounts in devcontainer.json.
Actionable closing
When you finish working in the container, you can close it and continue locally:
- Click the "Dev Container: …" indicator in the status bar and choose "Remote-Containers: Reopen Folder Locally".
- All source changes remain in the workspace; only the container‑specific state (installed packages, running processes) is discarded.
This gives you a deterministic environment for team collaboration while preserving the flexibility to switch back to a native workflow when needed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.