Dev Containers
A comprehensive guide to development containers for reproducible research environments. Dev containers define your entire development environment -- editor extensions, tools, runtimes, and dependencies -- as code in a devcontainer.json file. This skill covers devcontainer.json configuration, features, language-specific templates, multi-container setups with Docker Compose, GitHub Codespaces integration, and lifecycle hooks. Dev containers ensure that every contributor works in an identical environment, eliminating "works on my machine" issues.
Resources in This Skill
This skill includes supporting materials for dev container tasks:
References (detailed guides -- consult the table of contents in each file and read specific sections as needed):
references/devcontainer-json.md- Complete devcontainer.json reference: lifecycle scripts, remoteUser, mounts, environment variables, secrets forwarding, and Docker Compose integrationreferences/features-and-customization.md- Features and customization: official features, community features, creating custom features, VS Code customizations, Codespaces prebuilds, dotfiles, and machine types
Assets (ready-to-use devcontainer.json templates):
assets/python-devcontainer.json- Python devcontainer with Pylance, Jupyter, Ruff, and scientific computing extensionsassets/rust-devcontainer.json- Rust devcontainer with rust-analyzer, LLDB debugger, and cargo toolsassets/node-devcontainer.json- Node.js devcontainer with ESLint, Prettier, and testing extensions
Quick Reference Card
Minimal devcontainer.json
// .devcontainer/devcontainer.json
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/python:1": { "version": "3.12" }
},
"customizations": {
"vscode": {
"extensions": ["ms-python.python"]
}
},
"postCreateCommand": "pip install -e '.[dev]'"
}
Key Properties
| Property | Purpose | Example |
|---|---|---|
image |
Base container image | "mcr.microsoft.com/devcontainers/python:3.12" |
build.dockerfile |
Custom Dockerfile | "Dockerfile" |
features |
Add tools/runtimes | {"ghcr.io/devcontainers/features/node:1": {}} |
forwardPorts |
Auto-forward ports | [8000, 5432] |
postCreateCommand |
Run after container create | "pip install -e '.[dev]'" |
postStartCommand |
Run on every start | "git fetch --all" |
remoteUser |
Non-root user | "vscode" |
mounts |
Additional volumes | See reference |
customizations.vscode.extensions |
VS Code extensions | ["ms-python.python"] |
customizations.vscode.settings |
VS Code settings | {"python.defaultInterpreterPath": "/usr/local/bin/python"} |
File Location
Dev container configuration lives in one of these locations:
.devcontainer/devcontainer.json # standard (recommended)
.devcontainer.json # root-level alternative
.devcontainer/<name>/devcontainer.json # named configurations
When to Use
Use this skill when you need to:
- Set up a reproducible development environment for a research project
- Configure VS Code extensions and settings for a team
- Create GitHub Codespaces configurations for instant cloud development
- Add development tools (linters, formatters, debuggers) to a container
- Set up multi-container development environments (app + database + cache)
- Configure language-specific development environments (Python, Rust, Node.js)
- Customize dev container lifecycle (install dependencies on create, run setup scripts)
- Enable GPU access in development containers
- Share consistent development environments across a team or lab
devcontainer.json Structure
The devcontainer.json file is the core configuration. It can reference a pre-built image or a custom Dockerfile.
Image-Based Configuration
The simplest approach uses a pre-built image:
{
"name": "Python 3.12",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"postCreateCommand": "pip install -e '.[dev]'",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance"
]
}
}
}
Dockerfile-Based Configuration
For custom environments, point to a Dockerfile:
{
"name": "Custom Environment",
"build": {
"dockerfile": "Dockerfile",
"context": "..",
"args": {
"PYTHON_VERSION": "3.12"
}
},
"postCreateCommand": "pip install -e '.[dev]'"
}
Docker Compose Configuration
For multi-container setups (app + database, etc.):
{
"name": "Full Stack",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"postCreateCommand": "pip install -e '.[dev]'"
}
See references/devcontainer-json.md for the complete schema reference.
Pre-Built vs Custom Dockerfiles
Pre-Built Images (Recommended for Most Projects)
Microsoft publishes dev container images with common tools pre-installed:
| Image | Contents |
|---|---|
mcr.microsoft.com/devcontainers/base:ubuntu |
Ubuntu with git, zsh, common tools |
mcr.microsoft.com/devcontainers/python:3.12 |
Python with pip, pylint, venv |
mcr.microsoft.com/devcontainers/typescript-node:22 |
Node.js with npm, yarn |
mcr.microsoft.com/devcontainers/rust:1 |
Rust with cargo, rustfmt, clippy |
mcr.microsoft.com/devcontainers/universal:2 |
Multi-language (Python, Node, Go, Java, .NET) |
Advantages: Fast startup, no build step, maintained by Microsoft. Disadvantages: May include tools you don't need, less control over versions.
Custom Dockerfile (For Specialized Needs)
Use a custom Dockerfile when you need:
- Specific system libraries (HDF5, GDAL, FFTW)
- Exact version pinning beyond what features offer
- Private package repositories
- GPU development tools
# .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/python:3.12
# Install system libraries for scientific computing
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libhdf5-dev \
libgdal-dev \
libfftw3-dev && \
rm -rf /var/lib/apt/lists/*
# Install Python tools
RUN pip install --no-cache-dir \
ruff mypy pytest jupyter
Features
Features are modular, shareable units of installation code. They add tools, runtimes, or configuration to a dev container without modifying the Dockerfile.
{
"features": {
// Official features (from devcontainers org)
"ghcr.io/devcontainers/features/python:1": { "version": "3.12" },
"ghcr.io/devcontainers/features/node:1": { "version": "22" },
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/github-cli:1": {},
// Community features
"ghcr.io/devcontainers-contrib/features/ruff:1": {},
"ghcr.io/devcontainers-contrib/features/poetry:2": {}
}
}
Key benefits:
- Composable: mix and match tools from different sources
- Versioned: pin to major/minor versions for stability
- Cacheable: features are cached for faster rebuilds
See references/features-and-customization.md for the full features reference.
Language-Specific Configurations
Python (Scientific Computing)
{
"name": "Python Science",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-toolsai.jupyter",
"charliermarsh.ruff"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
}
}
}
},
"postCreateCommand": "pip install -e '.[dev]'"
}
See assets/python-devcontainer.json for a complete template.
Rust
{
"name": "Rust",
"image": "mcr.microsoft.com/devcontainers/rust:1",
"customizations": {
"vscode": {
"extensions": [
"rust-lang.rust-analyzer",
"vadimcn.vscode-lldb"
],
"settings": {
"rust-analyzer.check.command": "clippy"
}
}
},
"postCreateCommand": "cargo build"
}
See assets/rust-devcontainer.json for a complete template.
Node.js
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/typescript-node:22",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
},
"postCreateCommand": "npm install"
}
See assets/node-devcontainer.json for a complete template.
Multi-Container Dev Environments
Use Docker Compose when your development environment requires multiple services:
# .devcontainer/docker-compose.yml
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
command: sleep infinity
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: devpassword
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
pgdata:
// .devcontainer/devcontainer.json
{
"name": "Full Stack",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"forwardPorts": [5432, 6379],
"postCreateCommand": "pip install -e '.[dev]'"
}
GitHub Codespaces
Dev containers are the configuration format for GitHub Codespaces. Any repository with a .devcontainer/devcontainer.json can be opened in Codespaces.
Codespaces-specific settings:
{
"hostRequirements": {
"cpus": 4,
"memory": "8gb",
"storage": "32gb"
},
"secrets": {
"API_KEY": {
"description": "API key for the data service",
"documentationUrl": "https://example.com/docs/api-keys"
}
}
}
Prebuilds: Configure prebuilds in your repository settings to pre-build the dev container image, reducing Codespace startup time from minutes to seconds.
VS Code Extensions and Settings
Extensions
Extensions are installed automatically when the container is created:
{
"customizations": {
"vscode": {
"extensions": [
// Use the full extension ID from the VS Code marketplace
"ms-python.python",
"ms-python.vscode-pylance",
"ms-toolsai.jupyter",
"charliermarsh.ruff",
"eamodio.gitlens",
"github.copilot"
]
}
}
}
Settings
Override VS Code settings for the dev container:
{
"customizations": {
"vscode": {
"settings": {
"editor.formatOnSave": true,
"editor.rulers": [88],
"files.trimTrailingWhitespace": true,
"terminal.integrated.defaultProfile.linux": "zsh",
"python.testing.pytestEnabled": true
}
}
}
}
Lifecycle Hooks
Dev containers support several lifecycle hooks that run at different points:
| Hook | When It Runs | Use Case |
|---|---|---|
initializeCommand |
Before container build (on host) | Check prerequisites |
onCreateCommand |
After container is created (first time only) | One-time setup |
updateContentCommand |
After create, and on content updates | Install dependencies |
postCreateCommand |
After create + updateContent | Install dev deps, setup |
postStartCommand |
Every time container starts | Fetch latest data |
postAttachCommand |
Every time VS Code attaches | Start background services |
{
"postCreateCommand": "pip install -e '.[dev]' && pre-commit install",
"postStartCommand": "git fetch --all --prune"
}
Commands can be strings (run in shell) or arrays (exec form):
{
"postCreateCommand": {
"pip": "pip install -e '.[dev]'",
"pre-commit": "pre-commit install",
"data": "python scripts/download_test_data.py"
}
}
GPU in Dev Containers
NVIDIA GPU
{
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"features": {
"ghcr.io/devcontainers/features/nvidia-cuda:1": {
"installCudnn": true,
"cudaVersion": "12.4"
}
},
"runArgs": ["--gpus", "all"],
"postCreateCommand": "pip install torch --index-url https://download.pytorch.org/whl/cu124"
}
Codespaces GPU
GPU-enabled Codespaces require a machine type with GPU support (available on GitHub Enterprise or by request):
{
"hostRequirements": {
"gpu": true
}
}
Common Mistakes
Putting devcontainer.json in the wrong location -- It must be in
.devcontainer/devcontainer.jsonor.devcontainer.jsonat the repository root. Nested paths likesrc/.devcontainer/are not detected.Not using
postCreateCommandfor dependency installation -- Installing dependencies in the Dockerfile means they are baked into the image and not updated. UsepostCreateCommandto install from the current lockfile.Forgetting
forwardPorts-- Ports exposed by services (databases, dev servers) are not automatically forwarded. Add them toforwardPortsor they will not be accessible from the host.Using root as the default user -- Dev container images create a
vscodeuser by default. Ensure file permissions work for this user. Set"remoteUser": "vscode"explicitly.Not caching Codespaces prebuilds -- Without prebuilds, every Codespace creation runs the full build. Enable prebuilds in repository settings to reduce startup time.
Installing too many features -- Each feature adds layers and startup time. Only add features you actually use. Prefer a custom Dockerfile for complex setups.
Hardcoding paths -- Use
${containerWorkspaceFolder}instead of hardcoded paths. The workspace mount point may differ between local dev containers and Codespaces.Missing Docker Compose volumes -- Without a volume mount, source code changes on the host are not reflected in the container. Use
- ..:/workspace:cachedfor bind mounts.
Best Practices
- Place
devcontainer.jsonin.devcontainer/for discoverability - Use pre-built images from
mcr.microsoft.com/devcontainers/when possible - Pin feature versions to major version (
features/python:1, not:latest) - Use
postCreateCommandfor dependency installation (not Dockerfile RUN) - Set
remoteUserto a non-root user (typically"vscode") - Add
forwardPortsfor all services your development workflow needs - Include essential VS Code extensions in
customizations.vscode.extensions - Use
postStartCommandfor actions that should run on every container start - Enable Codespaces prebuilds for repositories with long build times
- Keep the dev container close to production (same OS, same Python version)
- Use named configurations (
.devcontainer/<name>/devcontainer.json) for multi-environment repos - Document required secrets in the
secretsproperty for Codespaces users - Test dev containers locally before relying on Codespaces
Resources
Official Documentation
- Dev Containers Specification: https://containers.dev/
- VS Code Dev Containers: https://code.visualstudio.com/docs/devcontainers/containers
- GitHub Codespaces: https://docs.github.com/en/codespaces
- devcontainer.json Reference: https://containers.dev/implementors/json_reference/
Features
- Official Features: https://github.com/devcontainers/features
- Community Features: https://github.com/devcontainers-contrib/features
- Feature Specification: https://containers.dev/implementors/features/
Templates
- Official Templates: https://github.com/devcontainers/templates
- Microsoft Dev Container Images: https://mcr.microsoft.com/en-us/catalog?search=devcontainers
Tools
- Dev Container CLI: https://github.com/devcontainers/cli
- GitHub Codespaces Prebuilds: https://docs.github.com/en/codespaces/prebuilding-your-codespaces