Skip to content

Dev Containers: Reproducible Development Environments

DodaTech Updated 2026-06-22 6 min read

In this tutorial, you'll learn dev containers including VS Code Dev Containers, devcontainer.json configuration, container features, and creating consistent development environments across your team.

Why Dev Containers Matter

Onboarding a new developer should take minutes, not days. Dev containers package the entire development environment -- language runtime, tools, extensions, and configuration -- into a portable container definition stored in your Repository. When a developer opens the project in VS Code, Dev Containers automatically builds and attaches to the container. No manual setup, no configuration drift.

By the end of this guide, you will create dev container configurations, customize them for different languages, and share them with your team.

What are Dev Containers?

Dev Containers are Docker containers configured as full-featured development environments. The configuration lives in a .devcontainer directory at the project root. VS Code's Dev Containers extension builds the container and connects to it, providing a seamless IDE experience inside the container.

flowchart LR
  A[Project Repo] --> B[.devcontainer/]
  B --> C[devcontainer.json]
  B --> D[Dockerfile]
  C --> E[Extensions]
  C --> F[Settings]
  C --> G[Ports]
  C --> H[Post-Create Commands]
  D --> I[Base Image]
  I --> J[OS + Runtime + Tools]

Basic Setup

Install the Dev Containers extension in VS Code:

Name: Dev Containers
Id: ms-vscode-remote.remote-containers

Project Structure

my-project/
├── .devcontainer/
│   ├── devcontainer.json
│   └── Dockerfile
├── src/
├── package.json
└── README.md

devcontainer.json

{
  "name": "Node.js Development",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "ms-vscode.vscode-typescript-next",
        "github.copilot]
      ],
      "settings": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "esbenp.prettier-vscode"
      }
    }
  },
  "forwardPorts": [3000, 5173],
  "postCreateCommand": "npm install",
  "remoteUser": "node"
}

Dockerfile

FROM node:20-slim

RUN apt-get update && apt-get install -y \
  git \
  curl \
  && rm -rf /var/lib/apt/lists/*

RUN npm install -g npm@latest

WORKDIR /workspace

Opening a Project in a Dev Container

  1. Clone the Repository
  2. Open in VS Code
  3. Run Dev Containers: Reopen in Container from the command palette
  4. VS Code builds the container (first time) and reopens the window

Expected Behavior

$ [Dev Containers] Starting Dev Container...
$ [Dev Containers] Building Docker image from Dockerfile...
$ [Dev Containers] Running postCreateCommand...
$ [Dev Containers] Container ready!

After the container starts, VS Code shows "Dev Container: Node.js Development" in the bottom-left status bar.

Language-Specific Configurations

Python Dev Container

{
  "name": "Python 3 Development",
  "build": {
    "dockerfile": "Dockerfile",
    "context": ".."
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance",
        "ms-python.black-formatter",
        "charliermarsh.ruff]
      ],
      "settings": {
        "python.defaultInterpreterPath": "/usr/local/bin/python",
        "python.testing.pytestEnabled": true,
        "python.testing.unittestEnabled": false
      }
    }
  },
  "forwardPorts": [8000],
  "postCreateCommand": "pip install --user -r requirements.txt",
  "remoteUser": "vscode"
}
FROM mcr.microsoft.com/devcontainers/python:3.12

RUN pip install --upgrade pip

EXPOSE 8000

Rust Dev Container

{
  "name": "Rust Development",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "rust-lang.rust-analyzer",
        "vadimcn.vscode-lldb",
        "tamasfe.even-better-toml",
        "serayuzgur.crates]
      ],
      "settings": {
        "rust-analyzer.checkOnSave.command": "clippy"
      }
    }
  },
  "features": {
    "ghcr.io/devcontainers/features/rust:1": {}
  },
  "postCreateCommand": "cargo build",
  "forwardPorts": [8080]
}

Features

Dev Container Features are reusable, self-contained units that add tools and runtimes to a container.

{
  "name": "Full Stack Development",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "features": {
    "ghcr.io/devcontainers/features/node:1": {
      "version": "20"
    },
    "ghcr.io/devcontainers/features/python:1": {
      "version": "3.12"
    },
    "ghcr.io/devcontainers/features/docker-in-docker:1": {},
    "ghcr.io/devcontainers/features/git:1": {},
    "ghcr.io/devcontainers/features/github-cli:1": {}
  }
}

Available Features

Feature Description
node Node.js and npm
python Python and pip
java JDK and Maven/Gradle
go Go compiler
rust Rust toolchain
docker-in-docker Docker inside the container
<a href="/devops/terraform/">Terraform</a> Terraform CLI
aws-cli AWS command-line tools

Environment Variables and Secrets

{
  "name": "Development with Secrets",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "containerEnv": {
    "NODE_ENV": "development",
    "DATABASE_HOST": "localhost"
  },
  "remoteEnv": {
    "GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}"
  }
}

Use .env files for secrets:

{
  "runArgs": ["--env-file", ".devcontainer/.env"]
}

Advanced Configuration

Multiple Container Setup

{
  "name": "Full Stack with Database",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "forwardPorts": [3000, 8080, 5432]
}
# .devcontainer/docker-compose.yml
version: '3.9'
services:
  app:
    build: .
    volumes:
      - ..:/workspace:cached
    command: sleep infinity
    environment:
      DATABASE_URL: postgresql://user:pass@db:5432/myapp
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp

Lifecycle Hooks

{
  "onCreateCommand": "echo 'Container created'",
  "updateContentCommand": "npm install",
  "postCreateCommand": "npm run build",
  "postStartCommand": "npm run dev &",
  "postAttachCommand": "echo 'Attached!'"
}

Sharing with Your Team

Store the .devcontainer directory in your Repository. When team members open the project, VS Code prompts them to reopen in the container.

git add .devcontainer/
git commit -m "Add dev container configuration"
git push

Common Errors

Problem Cause Fix
Docker is not running Docker not started Start Docker Desktop or Docker daemon
Failed to connect to bus Systemd not available Not needed -- dev containers don't use systemd
Permission denied when writing files UID mismatch Use remoteUser to match your host UID
Extension not found Extension ID misspelled Verify the extension ID from the marketplace
postCreateCommand failed Command error in container Check the logs in VS Code's Dev Containers output panel

Practice Questions

1. Where does the dev container configuration live in a project?

In a .devcontainer/ directory at the project root.

2. What is the purpose of postCreateCommand?

It runs a command after the container is created, typically for installing dependencies.

3. How do you use Docker Compose with dev containers?

Set dockerComposeFile and service in devcontainer.json to reference a Docker Compose configuration.

4. What are Dev Container Features?

Reusable units that add tools and runtimes to a container (e.g., Node.js, Python, Docker-in-Docker).

5. How do you forward ports from a dev container to your host machine?

Use the forwardPorts array in devcontainer.json.

Challenge

Create a dev container configuration for a full-stack project using Node.js with React frontend and Python backend. Include: both runtimes, database client tools, VS Code extensions for both languages, port forwarding for frontend and backend, and a post-create command that installs all dependencies.

Real-World Task

Take an existing project and create a .devcontainer/devcontainer.json configuration. Install the Dev Containers extension, reopen the project in the container, and verify that all development workflows work: running tests, starting the dev server, debugging with breakpoints, and using the integrated terminal. Share the configuration with your team by committing it to the Repository.

Do dev containers work with other editors?

Dev Containers is a VS Code feature. GitHub Codespaces also supports devcontainer.json. Other editors have similar features (JetBrains Gateway, Emacs with Docker).

What is the performance impact of dev containers?

Negligible on modern machines. Files are mounted as volumes, so editing is fast. CPU and memory overhead is minimal compared to running natively.

Can I use GPU acceleration in dev containers?

Yes. Use runArgs: ["--gpus", "all"] in devcontainer.json to access NVIDIA GPUs for ML/DL workloads.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro