Development Container
The authoritative development environment for a repository — reusable features provide the toolchains, and repository-specific lifecycle hooks finish the workspace.
- Kind
- Architecture
- Domain
- Environment & Tooling
- Applies at
.devcontainer/- Status
- Stable
- Source · managed
.devcontainer/README.md
01 Defines
A container definition, following the Development Containers specification, that provisions every tool, runtime, service, and utility needed to work on the repository, so a fresh rebuild is ready for development without manual bootstrapping.
02 Applies when
- A repository needs the same toolchain for every developer, editor, and automation surface.
- Tools and services must be provisioned before any project command runs.
- Common tooling can be expressed as reusable devcontainer features rather than hand-written installs.
03 Boundaries
- Provisioning the environment is in scope; project operations such as restore, generate, build, and test are not.
- Only tooling the repository owns or directly uses is provisioned; platform integration tooling only where that boundary is documented.
- The configuration does not depend on one hosted editor or source-control provider.
Expected behaviour
- 01
devcontainer.jsondeclares settings, mounts, features, and one lifecycle command per phase. - 02
devcontainer-lock.jsonrecords the resolved version and digest of every feature. - 03The
Dockerfilestays minimal and delegates toolchain installation to features. - 04Reusable toolchains come from devcontainer features; repository-specific setup comes from lifecycle scripts.
- 05Every lifecycle command delegates to the shared
run-parts.shrunner. - 06Any tool that can run the Dev Containers CLI can build and use the environment.
Behaviour#
The development container is responsible for the environment; the repository’s commands only use it. Developers are not expected to run a separate bootstrap step to install tools after the container is built — if a tool is needed, the container provides it.
The definition is layered. A small base image sets the operating system and primary runtime. Devcontainer features add reusable capabilities on top. The Devcontainer Lifecycle adds the last, repository-specific layer.
- 01
Base image
Dockerfile— oneFROMline, kept minimal - 02
Features
Toolchains, CLIs, and services, pinned by
devcontainer-lock.json - 03
Container
Mounts,
remoteUser,containerEnv, and editor customisations - 04
Lifecycle
Repository-specific hooks run by
run-parts.shDevcontainer Lifecycle
- .devcontainer/
- devcontainer.json Settings, mounts, features, lifecycle commands
- devcontainer-lock.json Resolved feature versions and digests
- Dockerfile Base image; direct customisation kept minimal
- lifecycle/ Shared runner and hook directories Devcontainer Lifecycle
Features first#
A devcontainer feature is the preferred way to install a common toolchain,
configure a runtime dependency, or expose a development service. When a suitable
upstream feature exists, it is used instead of re-implementing the install in a
lifecycle script or the Dockerfile.
When no upstream feature fits, or organisation-specific behaviour is required, a
local feature may be developed under ./features. It stays generic enough to be
extracted and reused by other repositories later. Workspace initialisation,
shell customisation, and other repository-specific behaviour stay out of
features and belong in lifecycle scripts.
Tool versions may come from shared metadata such as .tool-versions, or be
pinned directly in devcontainer or CI configuration. Where consistency matters,
the pins are shared or coordinated.
Examples#
Every lifecycle command in this repository delegates to the same runner, and toolchains arrive as features:
{
"build": { "dockerfile": "Dockerfile" },
"initializeCommand": "bash .devcontainer/lifecycle/run-parts.sh initialize",
"postStartCommand": "bash .devcontainer/lifecycle/run-parts.sh post-start",
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/terraform:1": {},
"ghcr.io/devcontainers/features/hugo:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": { "moby": true }
}
}
The environment is driven entirely from the Dev Containers CLI, so any editor or automation surface can wrap the same commands:
devcontainer up --workspace-folder . # Build and start
devcontainer exec --workspace-folder . make doctor # Verify the environment
devcontainer exec --workspace-folder . make validate # Run project validation
devcontainer build --workspace-folder . # Prebuild or warm the cache
make doctor is the
Environment Doctor
: it reports what the
container was expected to provide and what is missing.
Connections
How Development Container relates to the library
Relied on by
- Command Surface An identical root Makefile in every repository, with the repository’s own components …
- Environment Doctor make doctor reports which required tools and repository files are present or missing — a …
- Linter Configuration A single .linter/ directory holds the repository’s own lint configuration and overrides, …