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 container - •
image: Pre-built Docker image to use - •
build: Build configuration (dockerfile, context, args) - •
dockerComposeFile: Path to docker-compose.yml file - •
service: Docker Compose service name to connect to
Environment Setup:
- •
workspaceFolder: Path where workspace is mounted (default:/workspaces/<project-name>) - •
workspaceMount: Custom workspace mount configuration - •
mounts: Additional volume/bind mounts - •
containerEnv: Environment variables for the container - •
remoteUser: 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 created - •
updateContentCommand: Runs when container config changes - •
postCreateCommand: Runs after container creation (often used fornpm install,pip install) - •
postStartCommand: Runs every time the container starts - •
postAttachCommand: Runs every time you attach to the container
VS Code Customization:
- •
customizations.vscode.extensions: Extensions to install in the container - •
customizations.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 options - •
install.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 Container - •
Dev Containers: Rebuild Container - •
Dev Containers: Add Dev Container Configuration Files... - •
Dev Containers: Configure Container Features - •
Dev 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