Development Containers Expert
Expert guidance for working with Development Containers (devcontainers) - a standardized way to create fully-featured, containerized development environments.
When to Use This Skill
Activate this skill when:
- Creating or configuring devcontainer.json files
- Setting up containerized development environments in VS Code
- Working with dev container Templates or Features
- Troubleshooting devcontainer issues
- Integrating development containers with Docker or Docker Compose
- User mentions: devcontainers, dev containers, devcontainer.json, VS Code containers, containerized development, or development environment setup
What Are Development Containers?
A development container (dev container) is a running Docker container with a well-defined tool/runtime stack and its prerequisites. The configuration is defined in a devcontainer.json file that tells VS Code (or other supporting tools) how to access or create a development container.
Key Benefits:
- Consistency: Same environment for all developers
- Repeatability: Quickly recreate environments
- Isolation: Separate tools/libraries per project
- Onboarding: New developers get productive faster
- CI/CD Integration: Same environment for local dev and testing
The Specification: Dev containers follow the open Development Containers Specification maintained by the devcontainers community.
Prerequisites
Required Software
Docker
- Windows: Docker Desktop 2.0+ (Windows 10 Pro/Enterprise or Windows 10 Home 2004+ with WSL 2)
- macOS: Docker Desktop 2.0+
- Linux: Docker CE/EE 18.06+ and Docker Compose 1.21+
VS Code
- Visual Studio Code or VS Code Insiders
- Dev Containers extension (
ms-vscode-remote.remote-containers)
System Resources
- Minimum: 1 GB RAM
- Recommended: 2 GB RAM and 2-core CPU
Installation Steps
Windows/macOS:
- Install Docker Desktop from https://www.docker.com/products/docker-desktop
- For Windows WSL 2: Enable "Use the WSL 2 based engine" in Docker Desktop settings
- Install VS Code from https://code.visualstudio.com/
- Install the Dev Containers extension from the VS Code Extensions marketplace
Linux:
- Install Docker CE/EE following official instructions for your distribution
- Add your user to the docker group:
sudo usermod -aG docker $USER - Sign out and back in for changes to take effect
- Install VS Code
- Install the Dev Containers extension
Creating a devcontainer.json File
The devcontainer.json file is the core configuration for your dev container. It can be placed in one of two locations:
.devcontainer/devcontainer.json(recommended for complex setups).devcontainer.json(root of project)
Quick Start: Using a Template
The easiest way to create a dev container is using a pre-built Template:
- Open Command Palette in VS Code:
F1orCmd/Ctrl+Shift+P - Run:
Dev Containers: Add Dev Container Configuration Files... - Select a Template based on your tech stack (e.g., Node.js, Python, Go, Java)
- Customize with Features (optional) - add tools like Git, GitHub CLI, Docker-in-Docker
- Reopen in Container: Run
Dev Containers: Reopen in Container
VS Code will build the container and reopen your workspace inside it.
Basic devcontainer.json Structure
Minimal Example (Using Pre-built Image):
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"forwardPorts": [3000],
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
}
}
Using a Dockerfile:
{
"name": "My Custom Container",
"build": {
"dockerfile": "Dockerfile",
"context": "..",
"args": {
"VARIANT": "18"
}
},
"forwardPorts": [3000, 5000],
"postCreateCommand": "npm install",
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash"
},
"extensions": ["dbaeumer.vscode-eslint"]
}
}
}
Using Docker Compose:
{
"name": "My Multi-Container App",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"forwardPorts": [3000],
"postCreateCommand": "npm install",
"customizations": {
"vscode": {
"extensions": ["dbaeumer.vscode-eslint"]
}
}
}
Key Configuration Properties
Container Definition:
name: Display name for the containerimage: Pre-built Docker image to usebuild: Build configuration (dockerfile, context, args)dockerComposeFile: Path to docker-compose.yml fileservice: Docker Compose service name to connect to
Environment Setup:
workspaceFolder: Path where workspace is mounted (default:/workspaces/<project-name>)workspaceMount: Custom workspace mount configurationmounts: Additional volume/bind mountscontainerEnv: Environment variables for the containerremoteUser: User to run as inside container (default: root or image default)
Port Forwarding:
forwardPorts: Array of ports to forward (e.g.,[3000, 8080])portsAttributes: Configure port labels, protocols, and visibility
Lifecycle Scripts:
onCreateCommand: Runs once when container is createdupdateContentCommand: Runs when container config changespostCreateCommand: Runs after container creation (often used fornpm install,pip install)postStartCommand: Runs every time the container startspostAttachCommand: Runs every time you attach to the container
VS Code Customization:
customizations.vscode.extensions: Extensions to install in the containercustomizations.vscode.settings: VS Code settings for the container
Working with Dev Container Features
Features are self-contained, shareable units of installation code that add tools, runtimes, or libraries to your container.
Adding Features
Method 1: During Setup
When running Dev Containers: Add Dev Container Configuration Files..., you'll be prompted to select Features.
Method 2: Add to Existing Config
- Open Command Palette:
F1 - Run:
Dev Containers: Configure Container Features - Select Features to add
Method 3: Edit devcontainer.json Directly
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/git:1": {
"version": "latest"
},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"moby": true
}
}
}
Popular Features
Browse all at https://containers.dev/features:
- node, python, go, rust, java, dotnet - Language runtimes
- git, github-cli, azure-cli, aws-cli - CLI tools
- docker-in-docker, kubectl-helm-minikube - Container/K8s tools
- common-utils - Essential utilities (zsh, oh-my-zsh, etc.)
Pinning Feature Versions
Features follow semantic versioning. You can pin to specific versions:
"features": {
"ghcr.io/devcontainers/features/node:1": {}, // Latest v1.x.x
"ghcr.io/devcontainers/features/python:1.0": {}, // Latest v1.0.x
"ghcr.io/devcontainers/features/go:1.0.0": {} // Exact version 1.0.0
}
Creating Custom Features
You can create your own Features using the feature-starter template. Each Feature is a folder with:
devcontainer-feature.json- Metadata and optionsinstall.sh- Installation script
Common Workflows
Open Local Project in Container:
- Open project in VS Code
- Run:
Dev Containers: Reopen in Container(F1) - Select Template if no devcontainer.json exists
- VS Code builds and reopens in container
Clone Repository in Container Volume (better performance on Windows/macOS):
- Run:
Dev Containers: Clone Repository in Container Volume... - Enter Git URL or select from GitHub
- Choose Template if needed
Open GitHub PR:
- Run:
Dev Containers: Clone Repository in Container Volume... - Paste GitHub PR URL
- VS Code opens PR with GitHub Pull Requests extension
Rebuild Container (after config changes):
Dev Containers: Rebuild Container- OR
Dev Containers: Rebuild Container Without Cache(full rebuild)
Attach to Running Container:
- Run:
Dev Containers: Attach to Running Container... - Select container from list
Advanced Configuration
Monorepos: Multiple Devcontainers
Important Limitation: Multi-root workspaces (.code-workspace files) open all folders in the same container. To use different containers per package, open each folder separately.
Pattern 1: Separate Package Containers (different tech stacks)
monorepo/
├── apps/
│ ├── frontend/.devcontainer/devcontainer.json
│ └── backend/.devcontainer/devcontainer.json
Frontend (.devcontainer/devcontainer.json):
{
"name": "Frontend",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"workspaceFolder": "/workspaces/monorepo/apps/frontend",
"workspaceMount": "source=${localWorkspaceFolder}/../..,target=/workspaces/monorepo,type=bind"
}
Workflow:
- Single package: Right-click
frontend/→ "Open Folder in Container" - Multiple packages: Open separate VS Code windows, one per package
Pattern 2: Unified Polyglot Container (all tools in one)
{
"name": "Monorepo All",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node:1": {"version": "20"},
"ghcr.io/devcontainers/features/python:1": {"version": "3.11"},
"ghcr.io/devcontainers/features/go:1": {}
}
}
Pattern 3: Docker Compose Multi-Container (services in separate containers)
Use Docker Compose when packages need to run simultaneously (frontend + backend + db):
services:
frontend:
build: ./apps/frontend
volumes: [".:/workspace:cached"]
backend:
build: ./apps/backend
volumes: [".:/workspace:cached"]
db:
image: postgres:14
{
"name": "Monorepo",
"dockerComposeFile": "docker-compose.yml",
"service": "frontend",
"workspaceFolder": "/workspace"
}
Choose "frontend" or "backend" as primary service. Access other containers via docker exec or attach in separate windows.
Advanced Topics
For in-depth coverage of advanced scenarios, see the references/ directory:
- Pre-building Images - Image caching, CI/CD workflows, supply-chain security
- Kubernetes Integration - Attach to K8s pods, cluster development
- Networking Fundamentals - Docker network modes, port forwarding, DNS, proxies
- Advanced Networking - VPN, network security, service mesh, load balancing
- Volume Performance - Optimize disk performance on Windows/macOS
- Container-in-Container - Docker-in-Docker for CI/CD testing
- Security Hardening - Non-root users, secrets management, capabilities
- Dotfiles & Personalization - Shell customization, tool configuration
- Recovery & Debugging - Fix build failures, inspect containers
Advanced Configuration (Quick Reference)
Using Docker Compose
docker-compose.yml:
services:
app:
build: .
volumes:
- .:/workspace:cached
command: sleep infinity
db:
image: postgres:14
environment:
POSTGRES_PASSWORD: example
devcontainer.json:
{
"name": "App with Database",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"postCreateCommand": "npm install"
}
Non-Root User (See SECURITY.md)
{
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"remoteUser": "node"
}
Custom Mounts and Environment (See SECURITY.md)
{
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,readonly,type=bind"
],
"containerEnv": {
"DATABASE_URL": "postgresql://localhost/mydb"
}
}
Troubleshooting (Quick Reference)
For comprehensive debugging guides, see references/RECOVERY_DEBUGGING.md.
Common Issues:
- Docker Not Running: Check
docker psworks. On Linux:sudo systemctl status docker - Port Already in Use: Find process with
lsof -i :<port>(macOS/Linux) ornetstat -ano | findstr :<port>(Windows) - Slow Performance: See VOLUME_PERFORMANCE.md for optimization strategies
- Build Failures: Use
Dev Containers: Reopen in Recovery Containerto debug. See RECOVERY_DEBUGGING.md - Permission Errors: Set
remoteUseror see SECURITY.md for non-root configuration
Best Practices
- Version Control - Commit
.devcontainer/so all developers use the same environment - Use Official Images - Start with
mcr.microsoft.com/devcontainers/for reliability - Pin Versions - Lock Feature and base image versions for reproducibility
- Security - Run as non-root, avoid committing secrets. See SECURITY.md
- Performance - Use volume mounts on Windows/macOS. See VOLUME_PERFORMANCE.md
- Test Regularly - Ensure new team members can build containers from scratch
- Document - Add comments explaining custom configurations
Pre-building and CI/CD
Pre-building images improves startup time and enables CI/CD integration. See references/PREBUILDING.md for comprehensive guides.
Quick Example (GitHub Actions):
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: devcontainers/ci@v0.3
with:
imageName: ghcr.io/${{ github.repository }}-devcontainer
cacheFrom: ghcr.io/${{ github.repository }}-devcontainer
push: always
runCmd: npm test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Resources
- Specification: https://containers.dev/
- VS Code Docs: https://code.visualstudio.com/docs/devcontainers/containers
- Templates: https://containers.dev/templates
- Features: https://containers.dev/features
- GitHub Org: https://github.com/devcontainers
- CLI Reference: https://github.com/devcontainers/cli
- Docker Images: https://github.com/devcontainers/images
Quick Reference
VS Code Commands (open with F1 or Cmd/Ctrl+Shift+P):
Dev Containers: Reopen in ContainerDev Containers: Rebuild ContainerDev Containers: Add Dev Container Configuration Files...Dev Containers: Configure Container FeaturesDev Containers: Clone Repository in Container Volume...Dev Containers: Attach to Running Container...Dev Containers: Show Container Log
Key Configuration Locations:
.devcontainer/devcontainer.json(recommended).devcontainer.json(alternative)- Dockerfile:
.devcontainer/Dockerfile - Docker Compose:
.devcontainer/docker-compose.yml