Devcontainer Lifecycle
Six ordered hook phases that take a development container from host-side preparation to an attached, ready workspace.
- Kind
- Lifecycle
- Domain
- Environment & Tooling
- Applies at
.devcontainer/lifecycle/- Status
- Stable
- Source · managed
.devcontainer/lifecycle/README.md
01 Defines
The repository-specific provisioning layer of a development container: one hook directory per Dev Container lifecycle command, each run in lexical order by a shared runner.
02 Applies when
- A repository needs workspace setup that a reusable devcontainer feature cannot provide.
- Setup must happen at a particular moment — before the build, on creation, after content sync, on every start, or on every attach.
- Startup checks or lightweight services must be true for every session.
03 Boundaries
- Reusable toolchains, SDKs, and CLIs belong in devcontainer features, not lifecycle scripts.
- Normal project operations — build, test, generate — are not environment provisioning.
- Makefile targets and general scripts use the environment; they never silently create it.
Expected behaviour
- 01Every Dev Container lifecycle command delegates to
run-parts.sh <event>, which runs the matching<event>.d/directory. - 02Scripts run in lexical order; numeric prefixes such as
10-and20-make the order visible when it matters. - 03Every script can be run again safely, and
initialize.d/is never assumed to run only once. - 04Phases before
post-createhold only the setup that later phases depend on. - 05
post-start.d/andpost-attach.d/stay fast, because they run on every start and every attach.
Behaviour#
The image and its features provide reusable tooling. The lifecycle layer provides everything specific to this repository: linking command wrappers, configuring the shell, restoring dependencies, and running lightweight startup checks. A freshly rebuilt container, lifecycle included, should be ready for development without any manual bootstrapping.
- host · may repeat initializeCommand Prepare host-side files a mount or build expects
- once on create onCreateCommand Container-local state later phases consume
- on content sync updateContentCommand Restore dependencies from lockfiles and manifests
- once after create postCreateCommand Last-mile workspace bootstrap
- every start postStartCommand Fast checks and lightweight services
- every attach postAttachCommand Human-facing guidance and auth prompts
- Restart containerpostStartCommand
- Detach and reattachpostAttachCommand
- Rebuild containerinitializeCommand
Between the hooks, the Dev Containers tooling builds the image, installs features, creates the container, and starts it. The hooks never replace those steps; they only add to them.
Directory layout#
- .devcontainer/lifecycle/
- initialize.d/ Host-side initialization hooks Initialize Phase
- on-create.d/ Early container creation hooks On-Create Phase
- update-content.d/ Workspace content refresh hooks Update-Content Phase
- post-create.d/ One-time workspace setup hooks Post-Create Phase
- post-start.d/ Hooks that run after each container start Post-Start Phase
- post-attach.d/ Hooks that run after each editor attach Post-Attach Phase
- run-parts.sh Shared lifecycle runner Run-Parts Hook Directories
Where setup belongs#
Devcontainer features
- Language runtimes, SDKs, and package managers
- CLIs and Docker-in-Docker support
- Anything worth sharing across repositories
Lifecycle scripts
- Linking repository-owned command wrappers
- Shell and profile configuration for this workspace
- Dependency restore driven by checked-in lockfiles
Examples#
Adding a hook is adding a file. This repository restores its pinned Node tooling once workspace content is available:
#!/usr/bin/env bash
set -euo pipefail
if [ -f package-lock.json ]; then
npm ci
else
npm install
fi
Any phase can be run by hand through the same runner, which is useful when debugging a hook without rebuilding the container:
bash .devcontainer/lifecycle/run-parts.sh post-create
bash .devcontainer/lifecycle/run-parts.sh post-start
bash .devcontainer/lifecycle/run-parts.sh post-attach
Connections
How Devcontainer Lifecycle relates to the library
Refined by
- Initialize Phase Host-side hooks that run before the container is built or created, preparing only the files and …
- On-Create Phase Early in-container hooks that create container-local state — user-home caches, CLI …
- Post-Attach Phase Human-facing hooks that run each time a developer or editor attaches — short guidance, …
- Post-Create Phase The last mile of workspace bootstrap — linking wrappers, configuring the shell, generating local …
- Post-Start Phase Fast, repeatable hooks that run on every container start to repair ephemeral state, verify …
- Update-Content Phase Hooks driven by repository content — lockfiles, manifests, checked-in configuration — that …