Dev Containers
A development container defines a repeatable coding environment. It is different from a production image: development containers contain tools for editing, testing, debugging, and local workflow, while production images should contain only what the application needs to run.
The Dev Container Specification uses .devcontainer/devcontainer.json as structured metadata that tools can read.
Single-container example
Create .devcontainer/devcontainer.json.
1{
2 "name": "python-api",
3 "build": {
4 "dockerfile": "Dockerfile",
5 "context": "..",
6 "target": "development"
7 },
8 "workspaceFolder": "/workspace",
9 "remoteUser": "app",
10 "forwardPorts": [8000],
11 "postCreateCommand": "pip install -r requirements-dev.txt"
12}
Use a development target in the Dockerfile.
1# syntax=docker/dockerfile:1
2FROM python:3-slim AS base
3RUN useradd --uid 10001 --create-home app
4WORKDIR /workspace
5
6FROM base AS development
7RUN apt-get update -y && \
8 apt-get install --no-install-recommends git curl -y && \
9 rm -rf /var/lib/apt/lists/*
10USER app
11
12FROM base AS runtime
13COPY --chown=app:app . .
14USER app
15CMD ["python", "app.py"]
Compose-based example
Use Compose when the coding environment needs databases, queues, or other services.
1{
2 "name": "api-stack",
3 "dockerComposeFile": "../compose.yaml",
4 "service": "api",
5 "runServices": ["api", "db"],
6 "workspaceFolder": "/workspace",
7 "remoteUser": "app",
8 "shutdownAction": "stopCompose"
9}
The Compose file owns the service topology. The devcontainer file tells development tools which service is the workspace.
Users
Use remoteUser for tools and terminals. Use containerUser only when every process in the dev container should run as that user. On Linux, the spec can update the remote user’s UID/GID to reduce bind-mount permission problems.
Do not rely on root as the default development user. A development environment that only works as root hides problems that production will later expose.
Features
Dev Container Features install common tools in a reusable way.
1{
2 "features": {
3 "ghcr.io/devcontainers/features/github-cli": {},
4 "ghcr.io/devcontainers/features/node": {
5 "version": "lts"
6 }
7 }
8}
Use features for development tools. Do not copy those tools into the production image unless the application truly needs them at runtime.
CI reuse
The same development container can be used in CI for linting, tests, and docs builds. Keep the CI command explicit.
1devcontainer up --workspace-folder .
2devcontainer exec --workspace-folder . pytest
Practical rules
Keep development and production targets separate.
Use Compose for multi-service development environments.
Use non-root users to catch permission problems early.
Keep secrets out of
devcontainer.json.Install editor and debug tools in development targets or features, not runtime images.
Document forwarded ports and post-create commands.