Contents
Well, it works on my machine ¯\_(ツ)_/¯
As engineers and developers, we constantly juggle different tools, dependencies, and environments, especially when building applications with fast-paced AI services. One project requires Python 3.10 with a specific set of modules, another demands Node.js 18 with a global package installed, and yet another needs a completely different toolchain. Switching between these setups often leads to broken dependencies, version mismatches, or hours spent troubleshooting environment issues.
Dev Containers in VS Code address these issues by providing a containerized development environment that can be versioned and shared within your project repository.
In this article, we’ll explore what Dev Containers are, how they work, their advantages, and how you can configure them to match your project needs.
What Are Dev Containers?
Dev Containers, originally introduced by Microsoft, are a feature in Visual Studio Code that allows you to create reproducible, containerized development environments using Docker. You basically define your environment in a JSON definition, from which VSCode builds a container and opens the project in it. The Dev Container Specification is now an open standard, maintained by the Dev Container Community under the Open Container Initiative (OCI), with contributions from Microsoft, GitHub, and other organizations.
Instead of dealing with dependency issues or installing tools manually, you define everything in a devcontainer.json
file. Your code and settings are either mounted or copied into the container, and all VS Code features – like extensions – run inside it. This makes switching between projects easy and ensures everything works the same, no matter where you’re coding. This also allows you to store your devcontainer.json
definition file in a repository alongside your project and eliminates the hassle of getting all the dependencies right, e.g. when sharing tutorials or entire projects.
Advantages of Using DevContainers
There are many advantages, some of them are:
- Dev environment in Git – You can store
devcontainer.json
configuration files inside your repository, making your dev environment portable. - Support for multiple languages & frameworks – Use predefined Docker images with the required dependencies.
- Customizable – Extend the environment with additional configurations.
- Works with GitHub Codespaces – Dev Containers form the basis of GitHub Codespaces, allowing cloud-based development.
- Supports CI/CD pipelines – Use the same containerized environment in CI/CD workflows.
- Reduces onboarding time – Eliminates the need to install dependencies manually.
- No more manual setup – Define all tools, libraries, and runtimes in a
devcontainer.json
file, and let VS Code handle the rest. - Encourages best practices – Enforces infrastructure-as-code principles for development setups.
- Run anywhere – Since Dev Containers are based on Docker, they can run in the cloud, on a local machine, or even in GitHub Codespaces.
- Safe experimentation – Test new dependencies or tools without breaking your local setup. Just rebuild the container if needed.
Dev Container Definition
The devcontainer.json
file contains the configurations and settings for your Dev Container in a JSON schema. This includes pre-packaged tools, VS Code extensions and settings, forwarded ports, and more. In a basic setup, you’ll need:
Property | Type | Description | Example |
---|---|---|---|
name | string | A name for the dev container displayed in the UI. | "name": "devcontainers-demo", |
image | string | The name of an image in a container registry (DockerHub, GitHub Container Registry, Azure Container Registry). | "image": "mcr.microsoft.com/devcontainers/base:ubuntu", |
features | object | Features are reusable, prepackaged, modular components that install tools, languages, or configurations in a Dev Container, e.g. Git. | features": { "ghcr.io/devcontainers/features/git": {} } |
customizations | object | Product specific properties, e.g. VS Code extension settings. |
|
postCreateCommand | string, array, object | Run commands inside the container after the creation. This command is the last of three that finalizes container setup when a dev container is created. It happens after updateContentCommand and once the dev container has been assigned to a user for the first time. | "postCreateCommand": "if [ -f \"requirements.txt\" ]; then pip install -r requirements.txt; fi && echo 'Post-creation setup complete ✅'", |
You can find all available properties in the official reference documentation: Dev Container metadata reference
How to Create Dev Containers
Creating a Dev Container is fairly simple. Let’s go through it step by step.
Step 1: Install Required Tools
- Install VS Code
- Install the Dev Containers extension (
ms-vscode-remote.remote-containers
) - Install Docker
Step 2: Prepare the Project Folder
Create a new project folder and open it in VSCode.
mkdir sample-project cd sample-project # Open the current folder in VS Code using the command below or right-click the folder in File Explorer and select "Open with Code" code .
Now, add the devcontainer.json
file. By default, it’s placed inside a .devcontainer
folder, but it can also be stored elsewhere. VS Code will automatically detect it anywhere within the project folder. Create the following file structure:
mkdir .devcontainer New-Item -Path .devcontainer\devcontainer.json -ItemType File
Your project folder now has the following structure:
/sample-project │── .devcontainer/ │ ├── devcontainer.json
Step 3: Add Dev Container Configuration
Here’s a definition I commonly use for my projects. It will:
- use the
base:ubuntu
image from the Microsoft container registry - install various features so that I don’t have to install them manually, e.g. PowerShell including modules
- install VS Code extensions
- configure VS Code settings for the container environment (and very important: load Clippy in VS Code Pets extension 😜)
- install Python modules from the
requirements.txt
file, if one exists - set my user name to
batman
{ "name": "devcontainers-demo", "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "features": { "ghcr.io/devcontainers/features/azure-cli:1": { "installBicep": true }, "ghcr.io/devcontainers/features/powershell:1": { "modules": "Az.Accounts, Az.Resources" }, "ghcr.io/devcontainers/features/common-utils:2": {}, "ghcr.io/devcontainers/features/git:1": {}, "ghcr.io/devcontainers/features/python:1": { "version": "latest" } }, "customizations": { "vscode": { "extensions": [ "formulahendry.auto-rename-tag", "ms-vscode.azurecli", "ms-azuretools.vscode-bicep", "ms-python.black-formatter", "sleistner.vscode-fileutils", "esbenp.prettier-vscode", "vsls-contrib.gitdoc", "GitHub.copilot", "GitHub.copilot-chat", "ms-toolsai.jupyter", "ms-python.python", "ms-python.vscode-pylance", "ms-python.debugpy", "oderwat.indent-rainbow", "wayou.vscode-todo-highlight", "vscode-icons-team.vscode-icons", "tonybaloney.vscode-pets" ], "settings": { "terminal.integrated.defaultProfile.linux": "bash", "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "vscode-pets.petSize": "medium", "vscode-pets.petType": "clippy", "workbench.iconTheme": "vscode-icons", "todohighlight.keywords": [ { "text": "FEATURE:", "color": "white", "backgroundColor": "#68ba7f" } ] } } }, "postCreateCommand": "if [ -f \"requirements.txt\" ]; then pip install -r requirements.txt; fi && echo 'Post-creation setup complete ✅'", "remoteUser": "batman", "forwardPorts": [], "mounts": [] }
Step 4: Build and Start the Dev Container
There are two common ways to start a Dev Container
- Open the Command Palette (
Ctrl + Shift + P
) and runDev Containers: Reopen in Container
- Click on the blue
Open a Remote Window
icon in the bottom left corner and runReopen in Container
VS Code will now build the container and open the project inside it, as indicated in the bottom left corner. You can also view the newly created container in Docker Desktop.
Dockerfile
You can also create a Dev Container from a Dockerfile. This makes sense when you need a customized development environment with specific dependencies, configurations, or tools that aren’t available in a base image.
For a more detailed explanation of using Dev Containers with a Dockerfile, check out this guide: Using Images, Dockerfiles, and Docker Compose
Manage and Maintain
Keep in mind that the container should not be treated as persistent. You should always be able to create a new container, so you should update any changes to the devcontainer.json
file. After editing the devcontainer.json
file, the container must be rebuilt. You might get prompted automatically after saving your devcontainer.json
file; otherwise, again, click on the blue Open a Remote Window
icon in the bottom left corner and run Rebuild Container
.
Cheat Sheet
I’ve started a GitHub project for cheat sheets and just added the first one on Dev Containers. It includes helpful quick links, examples, and references to the individual configurations.
Take a look and feel free to star the repo to stay up to date: Dev Containers Cheat Sheet
Dev Containers vs. GitHub Codespaces
A Dev Container is a locally hosted development environment that runs inside a Docker container using VS Code. GitHub Codespaces, on the other hand, is a cloud-based development environment that runs on GitHub’s infrastructure. It also uses Dev Containers under the hood, meaning the same devcontainer.json
file that configures a local Dev Container can be used to set up a Codespace in GitHub. This allows seamless switching between local and cloud development while maintaining the same setup.
Conclusion
Dev Containers in VS Code are a powerful tool for ensuring a consistent, reproducible, and customizable development environment. For me, it really helps with easy environment setup depending on the project and tools I need, bundled with version control inside a project. Give it a try!