Home / Developer Tools / DevContainers: Consistent Development Environments Across Teams
Developer Tools

DevContainers: Consistent Development Environments Across Teams

Development environment inconsistencies cause 'works on my machine' problems that waste time and frustrate teams. DevContainers solve this by defining...

What you will learn

Practical execution with concise explanations, real implementation patterns, and production-ready recommendations.

], "settings": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "eslint.validate": ["javascript", "typescript"] } }``` }, "forwardPorts": [3000, 9229], "postCreateCommand": "npm install", "remoteUser": "node" }


### Custom Dockerfile

**`.devcontainer/Dockerfile`:**

```dockerfile
FROM mcr.microsoft.com/devcontainers/python:3.11

# Install system dependencies
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
```text
&& apt-get -y install --no-install-recommends \
   postgresql-client \
   redis-tools \
   curl \
   jq

Install Python tools

RUN pip install --upgrade pip \

&& pip install black pylint pytest pytest-cov

Setup non-root user

ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=$USER_UID

USER $USERNAME

Configure shell

RUN echo 'export PS1="[\e[32m](devcontainer)[\e[m] \w $ "' >> ~/.bashrc


**`devcontainer.json` with Dockerfile:**

```json
{
  "name": "Python Development",
  "build": {
```text
"dockerfile": "Dockerfile",
"args": {
  "USERNAME": "vscode"
}```
  },
  "customizations": {
```text
"vscode": {
  "extensions": [
    "ms-python.python",
    "ms-python.vscode-pylance",
    "ms-python.black-formatter"
  ]
}```
  },
  "postCreateCommand": "pip install -r requirements.txt",
  "remoteUser": "vscode"
}

Multi-Container Development

Docker Compose Integration

.devcontainer/docker-compose.yml:

version: '3.8'

services:
  app:
```yaml
build:
  context: ..
  dockerfile: .devcontainer/Dockerfile
volumes:
  - ..:/workspace:cached
command: sleep infinity
networks:
  - dev-network
depends_on:
  - db
  - redis

db:

image: postgres:16
restart: unless-stopped
environment:
  POSTGRES_USER: devuser
  POSTGRES_PASSWORD: devpassword
  POSTGRES_DB: devdb
volumes:
  - postgres-data:/var/lib/postgresql/data
networks:
  - dev-network

redis:

image: redis:7
restart: unless-stopped
networks:
  - dev-network

volumes: postgres-data:

networks: dev-network:


**`devcontainer.json` with Compose:**

```json
{
  "name": "Full Stack Development",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "customizations": {
```text
"vscode": {
  "extensions": [
    "ms-azuretools.vscode-docker",
    "ms-python.python",
    "cweijan.vscode-postgresql-client2"
  ]
}```
  },
  "forwardPorts": [8000, 5432, 6379],
  "postCreateCommand": "pip install -r requirements.txt && python manage.py migrate",
  "remoteUser": "vscode"
}

Language-Specific Configurations

Python with Virtual Environment

.devcontainer/devcontainer.json:

{
  "name": "Python 3.11",
  "image": "mcr.microsoft.com/devcontainers/python:3.11",
  "features": {
```text
"ghcr.io/devcontainers/features/common-utils:2": {
  "installZsh": true,
  "configureZshAsDefaultShell": true
}```
  },
  "customizations": {
```text
"vscode": {
  "extensions": [
    "ms-python.python",
    "ms-python.vscode-pylance",
    "ms-python.black-formatter",
    "ms-python.isort",
    "njpwerner.autodocstring"
  ],
  "settings": {
    "python.defaultInterpreterPath": "/usr/local/bin/python",
    "python.linting.enabled": true,
    "python.linting.pylintEnabled": true,
    "python.formatting.provider": "black",
    "python.testing.pytestEnabled": true,
    "[python]": {
      "editor.formatOnSave": true,
      "editor.codeActionsOnSave": {
        "source.organizeImports": true
      }
    }
  }
}```
  },
  "postCreateCommand": "pip install -r requirements.txt -r requirements-dev.txt",
  "postStartCommand": "python --version && pip list"
}

.NET with SDK

.devcontainer/devcontainer.json:

{
  "name": ".NET 8.0",
  "image": "mcr.microsoft.com/devcontainers/dotnet:8.0",
  "features": {
```text
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers/features/powershell:1": {}```
  },
  "customizations": {
```text
"vscode": {
  "extensions": [
    "ms-dotnettools.csharp",
    "ms-dotnettools.csdevkit",
    "ms-dotnettools.vscode-dotnet-runtime",
    "visualstudioexptteam.vscodeintellicode-csharp"
  ],
  "settings": {
    "omnisharp.enableRoslynAnalyzers": true,
    "omnisharp.enableEditorConfigSupport": true,
    "dotnet.defaultSolution": "MyApp.sln"
  }
}```
  },
  "postCreateCommand": "dotnet restore && dotnet build",
  "remoteUser": "vscode"
}

Node.js with npm/Yarn

.devcontainer/devcontainer.json:

{
  "name": "Node.js 20 with TypeScript",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:20",
  "features": {
```text
"ghcr.io/devcontainers/features/node:1": {
  "version": "20",
  "nodeGypDependencies": true
}```
  },
  "customizations": {
```text
"vscode": {
  "extensions": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "ms-vscode.vscode-typescript-next",
    "orta.vscode-jest"
  ],
  "settings": {
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": true
    },
    "typescript.tsdk": "node_modules/typescript/lib"
  }
}```
  },
  "postCreateCommand": "npm install",
  "postStartCommand": "npm run dev",
  "forwardPorts": [3000, 5173],
  "portsAttributes": {
```text
"3000": {
  "label": "Application",
  "onAutoForward": "notify"
}```
  }
}

Java with Maven

.devcontainer/devcontainer.json:

{
  "name": "Java 21 with Maven",
  "image": "mcr.microsoft.com/devcontainers/java:21",
  "features": {
```text
"ghcr.io/devcontainers/features/java:1": {
  "version": "21",
  "installMaven": true,
  "installGradle": false
}```
  },
  "customizations": {
```text
"vscode": {
  "extensions": [
    "vscjava.vscode-java-pack",
    "vscjava.vscode-spring-boot-dashboard",
    "vmware.vscode-spring-boot"
  ],
  "settings": {
    "java.configuration.runtimes": [
      {
        "name": "JavaSE-21",
        "path": "/usr/local/sdkman/candidates/java/current"
      }
    ]
  }
}```
  },
  "postCreateCommand": "mvn clean install -DskipTests",
  "forwardPorts": [8080]
}

VS Code Integration

Remote - Containers Extension

Installation:

## Install extension
code --install-extension ms-vscode-remote.remote-containers






> **Architecture Overview:** **Usage:**

{
  "version": "0.2.0",
  "configurations": [
```json
{
  "name": "Python: FastAPI",
  "type": "python",
  "request": "launch",
  "module": "uvicorn",
  "args": [
    "main:app",
    "--reload",
    "--host", "0.0.0.0",
    "--port", "8000"
  ],
  "jinja": true,
  "justMyCode": false
},
{
  "name": "Node: Debug",
  "type": "node",
  "request": "launch",
  "program": "${workspaceFolder}/src/index.js",
  "restart": true,
  "console": "integratedTerminal"
}```
  ]
}

Tasks Configuration

.vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
```json
{
  "label": "Run Tests",
  "type": "shell",
  "command": "pytest tests/ -v --cov",
  "group": {
    "kind": "test",
    "isDefault": true
  },
  "presentation": {
    "reveal": "always",
    "panel": "new"
  }
},
{
  "label": "Start Database",
  "type": "shell",
  "command": "docker-compose up -d db",
  "problemMatcher": []
}```
  ]
}

GitHub Codespaces Integration

Configuration

.devcontainer/devcontainer.json for Codespaces:

{
  "name": "Codespaces Python",
  "image": "mcr.microsoft.com/devcontainers/python:3.11",
  "hostRequirements": {
```text
"cpus": 4,
"memory": "8gb",
"storage": "32gb"```
  },
  "customizations": {
```text
"codespaces": {
  "openFiles": [
    "README.md",
    "src/main.py"
  ]
}```
  },
  "secrets": {
```text
"GITHUB_TOKEN": {
  "description": "GitHub Personal Access Token"
}```
  },
  "postCreateCommand": "pip install -r requirements.txt && pre-commit install"
}

Lifecycle Scripts

.devcontainer/lifecycle/postCreate.sh:

#!/bin/bash

echo "Setting up development environment..."

## Install dependencies
pip install -r requirements.txt





## Setup pre-commit hooks
pre-commit install





## Initialize database
python manage.py migrate





## Create sample data
python manage.py loaddata fixtures/sample_data.json





echo "Setup complete! Ready to code."

Reference in devcontainer.json:

{
  "postCreateCommand": "bash .devcontainer/lifecycle/postCreate.sh",
  "postStartCommand": "python manage.py runserver 0.0.0.0:8000",
  "postAttachCommand": "git status"
}

Performance Optimization

Volume Mounts

Cached Mounts:

{
  "mounts": [
```text
"source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached"```
  ]
}

Named Volumes for Dependencies:

{
  "mounts": [
```text
"source=node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
"source=pip-cache,target=/home/vscode/.cache/pip,type=volume"```
  ]
}

BuildKit Cache

.devcontainer/Dockerfile with cache:

## syntax=docker/dockerfile:1
FROM mcr.microsoft.com/devcontainers/python:3.11





## Cache pip dependencies
RUN --mount=type=cache,target=/root/.cache/pip \
```python
pip install --upgrade pip setuptools wheel

Copy and install requirements with cache

COPY requirements.txt /tmp/ RUN --mount=type=cache,target=/root/.cache/pip \

pip install -r /tmp/requirements.txt





## Layer Optimization

```dockerfile





## Bad: Combines unrelated operations
RUN apt-get update && apt-get install -y \
```python
postgresql-client \
&& pip install django

Good: Separate layers for caching

RUN apt-get update && apt-get install -y postgresql-client RUN pip install django


## Team Adoption

### Documentation





**`DEVCONTAINER_SETUP.md`:**


> **Architecture Overview:** ## DevContainer Setup


## Clear Docker cache

docker system prune -a --volumes





```text

## Port Already in Use

Edit `.devcontainer/devcontainer.json` and change `forwardPorts`.





Sharing Configurations

.devcontainer/devcontainer.json in version control:

## Commit devcontainer configuration
git add .devcontainer/
git commit -m "Add DevContainer configuration"
git push origin main





Expected output:

To https://github.com/contoso/myapp.git
   abc1234..def5678  main -> main

Terminal output for git push

Organization Templates:

## Create template repository
git clone https://github.com/contoso/devcontainer-templates.git
cp -r devcontainer-templates/python/.devcontainer ./





Best Practices

  1. Version Control Everything: Commit all .devcontainer files to repository
  2. Use Official Images: Prefer mcr.microsoft.com/devcontainers/* images
  3. Minimal Base Images: Start with minimal images, add only required tools
  4. Non-Root User: Always specify remoteUser for security
  5. Port Forwarding: Document all forwarded ports in README
  6. Lifecycle Scripts: Use postCreateCommand for one-time setup only
  7. Secrets Management: Never hardcode secrets in devcontainer.json

Troubleshooting

Troubleshooting

Figure: Configuration and management dashboard with status overview.

Container Build Timeout:

Architecture Overview: ## Increase Docker memory allocation

Permission Errors:

{
  "remoteUser": "vscode",
  "containerUser": "vscode",
  "updateRemoteUserUID": true
}

Extension Not Loading:

Architecture Overview: ## Reinstall extensions in container

Architecture Decision and Tradeoffs

When designing development workflow solutions with Developer Tools, consider these key architectural trade-offs:

Approach Best For Tradeoff
Managed / platform service Rapid delivery, reduced ops burden Less customisation, potential vendor lock-in
Custom / self-hosted Full control, advanced tuning Higher operational overhead and cost

Recommendation: Start with the managed approach for most workloads and move to custom only when specific requirements demand it.

Validation and Versioning

  • Last validated: April 2026
  • Validate examples against your tenant, region, and SKU constraints before production rollout.
  • Keep module, CLI, and SDK versions pinned in automation pipelines and review quarterly.

Security and Governance Considerations

  • Apply least-privilege access using RBAC roles and just-in-time elevation for admin tasks.
  • Store secrets in managed secret stores and avoid embedding credentials in scripts or source files.
  • Enable audit logging, data protection policies, and periodic access reviews for regulated workloads.

Cost and Performance Notes

  • Define budgets and alerts, then monitor usage and cost trends continuously after go-live.
  • Baseline performance with synthetic and real-user checks before and after major changes.
  • Scale resources with measured thresholds and revisit sizing after usage pattern changes.

Official Microsoft References

  • https://learn.microsoft.com/visualstudio/
  • https://learn.microsoft.com/azure/devops/
  • https://learn.microsoft.com/github/

Public Examples from Official Sources

  • These examples are sourced from official public Microsoft documentation and sample repositories.
  • Documentation examples: https://learn.microsoft.com/visualstudio/
  • Sample repositories: https://github.com/microsoft/vscode-extension-samples
  • Prefer adapting these examples to your tenant, subscriptions, and governance requirements before production use.

Key Takeaways

  • DevContainers eliminate "works on my machine" problems with reproducible environments
  • Configuration as code enables consistent development across teams
  • Docker Compose supports multi-container development with databases and services
  • GitHub Codespaces provides cloud-based DevContainer environments
  • Performance optimizations like cached mounts and BuildKit reduce rebuild times

Next Steps

  • Explore Features for reusable DevContainer components
  • Implement Dev Container Templates for common project types
  • Integrate GitHub Actions to validate DevContainer builds in CI
  • Configure Pre-commit hooks within DevContainers for code quality

Additional Resources


Build once, develop anywhere.

Discussion