DevContainer Spec Reference
Config File Discovery
Section titled âConfig File DiscoveryâTools search for devcontainer.json in this order:
.devcontainer/devcontainer.json.devcontainer.json.devcontainer/<folder>/devcontainer.json(one level deep only)
Multiple files may coexist. When more than one is found, the tool should let the user choose. The search starts at the project workspace folder, typically the git repository root.
Three Configuration Scenarios
Section titled âThree Configuration Scenariosâ| Scenario | Required Fields | Notes |
|---|---|---|
| Image-based | image | Pulls a container image directly |
| Dockerfile-based | build.dockerfile | Builds from a Dockerfile |
| Docker Compose-based | dockerComposeFile, service | Uses Compose to orchestrate one or more services |
Compose configurations handle images and Dockerfiles natively, so image and build.dockerfile
are not used in that scenario.
devcontainer.json Properties
Section titled âdevcontainer.json PropertiesâGeneral Properties (All Scenarios)
Section titled âGeneral Properties (All Scenarios)â| Property | Type | Default | Description |
|---|---|---|---|
name | string | - | Display name for the dev container |
features | object | - | Feature IDs mapped to their options |
overrideFeatureInstallOrder | string[] | - | Override automatic Feature install ordering |
forwardPorts | (number|string)[] | [] | Ports to forward from container to host |
portsAttributes | object | - | Per-port configuration (see Port Attributes) |
otherPortsAttributes | object | - | Defaults for ports not listed in portsAttributes |
containerEnv | object | - | Env vars set on the container itself |
remoteEnv | object | - | Env vars injected by the tool post-ENTRYPOINT |
containerUser | string | root or last Dockerfile USER | User for all container operations |
remoteUser | string | same as containerUser | User for lifecycle hooks and tool processes |
updateRemoteUserUID | boolean | true | Sync UID/GID to local user (Linux only) |
userEnvProbe | enum | loginInteractiveShell | Shell type for probing env vars (none, interactiveShell, loginShell, loginInteractiveShell) |
overrideCommand | boolean | true (image/Dockerfile), false (Compose) | Replace default command with a sleep loop |
shutdownAction | enum | stopContainer or stopCompose | Action on close (none, stopContainer, stopCompose) |
init | boolean | false | Use tini init process |
privileged | boolean | false | Run in privileged mode |
capAdd | string[] | [] | Linux capabilities to add |
securityOpt | string[] | [] | Security options |
mounts | (string|object)[] | - | Additional mounts (Docker --mount syntax) |
customizations | object | - | Tool-specific properties (namespaced by tool) |
hostRequirements | object | - | See Host Requirements |
Image / Dockerfile Properties
Section titled âImage / Dockerfile Propertiesâ| Property | Type | Default | Description |
|---|---|---|---|
image | string | required (image scenario) | Container registry image |
build.dockerfile | string | required (Dockerfile scenario) | Path to Dockerfile, relative to devcontainer.json |
build.context | string | "." | Docker build context directory |
build.args | object | - | Docker build arguments |
build.options | string[] | [] | Extra Docker build CLI flags |
build.target | string | - | Multi-stage build target |
build.cacheFrom | string|string[] | - | Cache source images |
workspaceMount | string | - | Custom mount for source code |
workspaceFolder | string | - | Default path opened inside the container |
runArgs | string[] | [] | Extra docker run CLI flags |
appPort | int|string|array | [] | Legacy, use forwardPorts instead |
Docker Compose Properties
Section titled âDocker Compose Propertiesâ| Property | Type | Default | Description |
|---|---|---|---|
dockerComposeFile | string|string[] | required | Path(s) to Compose file(s) |
service | string | required | Primary service to connect to |
runServices | string[] | all services | Subset of services to start. The primary service is always started regardless. |
workspaceFolder | string | "/" | Default path opened inside the container |
Lifecycle Hooks
Section titled âLifecycle Hooksâ| Property | Type | Runs | When |
|---|---|---|---|
initializeCommand | string|string[]|object | On host | Initialization (may run multiple times) |
onCreateCommand | string|string[]|object | In container | First creation only |
updateContentCommand | string|string[]|object | In container | After content is available (creation only) |
postCreateCommand | string|string[]|object | In container | After user setup (creation only, background by default) |
postStartCommand | string|string[]|object | In container | Every container start |
postAttachCommand | string|string[]|object | In container | Every tool attachment |
waitFor | enum | - | Block until this stage completes. Default: updateContentCommand. Values: initializeCommand, onCreateCommand, updateContentCommand, postCreateCommand, postStartCommand |
Command type details:
- string: Executed via the default shell (
/bin/sh). - string[]: Direct exec, no shell interpretation.
- object: Keys are unique names, values are string or string[]. All entries run in parallel. Every entry must succeed for the stage to succeed.
Host Requirements
Section titled âHost Requirementsâ| Property | Type | Description |
|---|---|---|
hostRequirements.cpus | integer | Minimum CPU count |
hostRequirements.memory | string | Minimum RAM (suffix: tb, gb, mb, kb) |
hostRequirements.storage | string | Minimum storage (same suffixes) |
hostRequirements.gpu | boolean|string|object | true = required, "optional" = preferred, or {"cores": N, "memory": "Xgb"} |
Port Attributes
Section titled âPort AttributesâProperties inside portsAttributes entries:
| Property | Type | Default | Description |
|---|---|---|---|
label | string | - | Display name |
protocol | enum | - | http or https |
onAutoForward | enum | notify | notify, openBrowser, openBrowserOnce, openPreview, silent, ignore |
requireLocalPort | boolean | false | Require the same port number locally |
elevateIfNeeded | boolean | false | Auto-elevate permissions for low ports |
Variable Substitution
Section titled âVariable Substitutionâ| Variable | Usable In | Description |
|---|---|---|
${localEnv:VAR} | Any property | Host env var. Supports default: ${localEnv:VAR:fallback} |
${containerEnv:VAR} | remoteEnv only | Container env var. Supports default: ${containerEnv:VAR:fallback} |
${localWorkspaceFolder} | Any property | Full path to the opened local folder |
${containerWorkspaceFolder} | Any property | Full path inside the container |
${localWorkspaceFolderBasename} | Any property | Local folder basename only |
${containerWorkspaceFolderBasename} | Any property | Container folder basename only |
${devcontainerId} | name, lifecycle hooks, mounts, env vars, user properties, customizations | Stable unique ID across rebuilds |
Substitution happens at the time the value is applied (runtime, not build time).
${containerEnv} is restricted to remoteEnv because container env vars only exist after
the container is running.
Lifecycle
Section titled âLifecycleâCreation Flow
Section titled âCreation FlowâinitializeCommand (host, may run multiple times) | vImage build / pull (Features applied as Dockerfile layers) | vContainer creation (mounts, containerEnv, containerUser applied) | (remoteUser/remoteEnv NOT applied yet) vonCreateCommand (in container, with remoteUser/remoteEnv) | vupdateContentCommand (in container) | vpostCreateCommand (in container, background by default) | v[implementation-specific] (tool-specific init, e.g. extension install) | vpostStartCommand (in container) | vpostAttachCommand (in container)The waitFor property controls at which point the tool reports the environment as ready and
proceeds to implementation-specific steps. Default is updateContentCommand.
Resume Flow
Section titled âResume FlowâRestart containers | v[implementation-specific steps] | vpostStartCommand | vpostAttachCommandRemote env vars and user configuration apply during resume.
Hook Execution Details
Section titled âHook Execution Detailsâ- Commands within an object run in parallel. All must succeed.
- Feature-provided lifecycle hooks run before user-defined hooks, in Feature installation order.
onCreateCommand,updateContentCommand, andpostCreateCommandrun only on first creation.postStartCommandruns on every start (creation and resume).postAttachCommandruns on every tool attachment.- Remote env vars and
userEnvProberesults are available for all post-creation hooks.
Users and Permissions
Section titled âUsers and PermissionsâTwo distinct user concepts:
- Container User (
containerUserfor image/Dockerfile,userin Compose): Runs all container operations including the ENTRYPOINT. - Remote User (
remoteUser): Runs lifecycle hooks and tool processes. Defaults tocontainerUserif not set. This separation allows different permissions for container operations vs. developer activity.
updateRemoteUserUID
Section titled âupdateRemoteUserUIDâ- Linux only, default
true. - When enabled and a remote/container user is specified, the tool updates the image userâs UID/GID to match the local user before container creation.
- Prevents permission mismatches on bind mounts.
- Implementations may skip this when not using bind mounts or when the container engine provides automatic UID translation.
Environment Variables
Section titled âEnvironment VariablesâTwo classes:
| Type | Property | Set When | Available |
|---|---|---|---|
| Container | containerEnv | At container build/create time | Entire container lifecycle |
| Remote | remoteEnv | Post-ENTRYPOINT by the tool | Lifecycle hooks and tool processes |
Remote env vars support ${containerEnv:VAR} substitution since the container is already
running when they are applied.
userEnvProbe
Section titled âuserEnvProbeâTools probe the userâs environment using the configured shell type and merge the resulting
variables with remoteEnv for injected processes. This emulates the behavior developers
expect from their profile/rc files.
Workspace Mount and Folder
Section titled âWorkspace Mount and FolderâworkspaceMount(image/Dockerfile only): Defines the source mount for the workspace. The default is a bind mount of the local folder into/workspaces/<folder-name>.workspaceFolder: The default working directory inside the container.- Both should reference the repository root (where
.gitlives) for proper source control. - For monorepos,
workspaceFoldercan point to a subfolder whileworkspaceMounttargets the repo root.
Image Metadata
Section titled âImage MetadataâConfiguration can be baked into images via the devcontainer.metadata label. The label value
is a JSON string containing either:
- An array of metadata objects (one per Feature, plus one for the devcontainer.json config).
- A single top-level object.
The array format is preferred because subsequent builds can simply append entries.
Storable Properties
Section titled âStorable PropertiesâThese properties can appear in image metadata: forwardPorts, portsAttributes,
otherPortsAttributes, containerEnv, remoteEnv, remoteUser, containerUser,
updateRemoteUserUID, userEnvProbe, overrideCommand, shutdownAction, init,
privileged, capAdd, securityOpt, mounts, customizations, hostRequirements,
all lifecycle hooks (onCreateCommand through postAttachCommand), and waitFor.
Metadata Merge Rules
Section titled âMetadata Merge RulesâWhen merging image metadata with devcontainer.json, the local file is considered last
(highest priority where order matters).
| Strategy | Properties |
|---|---|
| Boolean OR (true if any is true) | init, privileged |
| Union without duplicates | capAdd, securityOpt |
| Union, last wins on conflicts | forwardPorts |
| Collected list (append in order) | All lifecycle hooks, entrypoint |
| Collected list, last wins on conflicts | mounts |
| Last value wins (scalar) | waitFor, containerUser, remoteUser, userEnvProbe, shutdownAction, updateRemoteUserUID, overrideCommand |
| Per-variable, last wins | remoteEnv, containerEnv |
| Per-port, last wins | portsAttributes |
| Last value wins | otherPortsAttributes |
| Maximum value wins | hostRequirements (cpus, memory, storage, gpu) |
| Tool-specific logic | customizations |
Features
Section titled âFeaturesâFeatures are modular, self-contained units that add tools, runtimes, and capabilities to dev containers without writing complex Dockerfiles.
Feature Structure
Section titled âFeature StructureâA Feature is a directory containing:
devcontainer-feature.json(metadata, required)install.sh(entrypoint script, required)- Additional supporting files (optional)
devcontainer-feature.json
Section titled âdevcontainer-feature.jsonâRequired
Section titled âRequiredâ| Property | Type | Description |
|---|---|---|
id | string | Unique within the repository, must match directory name |
version | string | Semver (e.g., 1.0.0) |
name | string | Human-friendly display name |
Optional Metadata
Section titled âOptional Metadataâ| Property | Type | Description |
|---|---|---|
description | string | Feature overview |
documentationURL | string | Docs link |
licenseURL | string | License link |
keywords | string[] | Search terms |
deprecated | boolean | Deprecation flag |
legacyIds | string[] | Previous IDs (for renaming) |
Configuration
Section titled âConfigurationâ| Property | Type | Description |
|---|---|---|
options | object | User-configurable parameters (see Feature Options) |
containerEnv | object | Env vars added as Dockerfile ENV before install.sh |
privileged | boolean | Requires privileged mode |
init | boolean | Requires tini init |
capAdd | string[] | Linux capabilities |
securityOpt | string[] | Security options |
entrypoint | string | Custom startup script path |
mounts | object | Additional mounts |
Dependencies
Section titled âDependenciesâ| Property | Type | Description |
|---|---|---|
dependsOn | object | Hard dependencies (recursive). Feature fails if unresolvable. Values include options and version. |
installsAfter | string[] | Soft ordering (non-recursive). Only affects ordering of already-queued Features. Ignored if the referenced Feature is not being installed. |
Lifecycle Hooks
Section titled âLifecycle HooksâFeatures can declare their own lifecycle hooks: onCreateCommand, updateContentCommand,
postCreateCommand, postStartCommand, postAttachCommand. Same types as the main config.
Customizations
Section titled âCustomizationsâ| Property | Type | Description |
|---|---|---|
customizations | object | Tool-specific config. Arrays merge as union, objects merge values. |
Feature Options
Section titled âFeature Optionsâ"options": { "optionId": { "type": "string|boolean", "description": "What this option controls", "proposals": ["val1", "val2"], "enum": ["strict1", "strict2"], "default": "val1" }}proposals: Suggested values, free-form input allowed.enum: Strict allowed values only.default: Fallback when the user provides nothing.
Option IDs are converted to environment variables for install.sh:
replace non-word chars with _ -> strip leading digits/underscores -> UPPERCASEWritten to devcontainer-features.env and sourced before the script runs.
Built-in Variables for install.sh
Section titled âBuilt-in Variables for install.shâ| Variable | Description |
|---|---|
_REMOTE_USER | Configured remote user |
_CONTAINER_USER | Container user |
_REMOTE_USER_HOME | Remote userâs home directory |
_CONTAINER_USER_HOME | Container userâs home directory |
Features always execute as root during image build.
Referencing Features
Section titled âReferencing FeaturesâIn devcontainer.json:
"features": { "ghcr.io/devcontainers/features/go:1": {}, "ghcr.io/user/repo/node:18": {"version": "18"}, "https://example.com/feature.tgz": {}, "./local-feature": {"optionA": "value"}}Three source types:
- OCI Registry:
<registry>/<namespace>/<id>[:<semver>] - HTTPS Tarball: Direct URL to
.tgz - Local Directory:
./pathrelative to devcontainer.json
Installation Order Algorithm
Section titled âInstallation Order AlgorithmâStep 1 - Build dependency graph:
- Traverse
dependsOnrecursively andinstallsAfternon-recursively. - Deduplicate using Feature Equality.
Step 2 - Assign round priority:
- Default: 0.
overrideFeatureInstallOrderassigns priorities:array_length - index(first item = highest priority).
Step 3 - Round-based sorting:
- Identify Features whose dependencies are all satisfied.
- From those, commit only Features with the maximum
roundPriority. - Return lower-priority Features to the worklist for the next round.
- Within a round, stable sort lexicographically by: resource name, version tag, options count, option keys/values, canonical name.
- If a round makes no progress, fail (circular dependency).
Feature Equality
Section titled âFeature Equalityâ| Source | Equal When |
|---|---|
| OCI Registry | Manifest digests match AND options are identical |
| HTTPS Tarball | Content hashes match AND options are identical |
| Local Directory | Always unique |
Dockerfile Layer Generation
Section titled âDockerfile Layer Generationâ- Each Featureâs
install.shruns as its own Dockerfile layer (for caching). containerEnvvalues becomeENVinstructions beforeinstall.shruns.install.shis invoked as:chmod +x install.sh && ./install.sh- Default shell:
/bin/sh. privilegedandinit: required if any Feature needs them (boolean OR across all).capAddandsecurityOpt: union across all Features.
Feature Lifecycle Hooks
Section titled âFeature Lifecycle Hooksâ- Feature hooks execute before user-defined hooks.
- Hooks run in Feature installation order.
- Object-syntax commands within a single Feature run in parallel.
- All hooks run from the project workspace folder.
Features Distribution (OCI)
Section titled âFeatures Distribution (OCI)âPackaging
Section titled âPackagingâDistributed as devcontainer-feature-<id>.tgz tarballs containing the Feature directory.
OCI Artifact Format
Section titled âOCI Artifact Formatâ| Artifact | Media Type |
|---|---|
| Config | application/vnd.devcontainers |
| Feature layer | application/vnd.devcontainers.layer.v1+tar |
| Collection metadata | application/vnd.devcontainers.collection.layer.v1+json |
<registry>/<namespace>/<id>[:version]
Example: ghcr.io/devcontainers/features/go:1.2.3
Version Tags
Section titled âVersion TagsâMultiple tags are pushed for each release: 1, 1.2, 1.2.3, and latest.
Collection Metadata
Section titled âCollection MetadataâAn auto-generated devcontainer-collection.json aggregates all Feature metadata in a namespace.
Published at <registry>/<namespace>:latest.
Manifest Annotations
Section titled âManifest AnnotationsâPublished manifests include a dev.containers.metadata annotation containing the escaped JSON
from devcontainer-feature.json.
Authentication
Section titled âAuthenticationâ- Docker config:
$HOME/.docker/config.json - Environment variable:
DEVCONTAINERS_OCI_AUTH(format:service|user|token)
Templates
Section titled âTemplatesâTemplates Specification | Templates Distribution | Templates Overview
Templates are pre-configured dev environment blueprints. They are not directly relevant to cribâs runtime behavior but are useful context for understanding the ecosystem.
Structure
Section titled âStructureâtemplate/ devcontainer-template.json .devcontainer.json (or .devcontainer/devcontainer.json) (supporting files)devcontainer-template.json
Section titled âdevcontainer-template.jsonâRequired: id, version, name, description.
Optional: documentationURL, licenseURL, platforms, publisher, keywords, options,
optionalPaths.
Option Substitution
Section titled âOption SubstitutionâTemplate options use ${templateOption:optionId} syntax. The tool replaces these placeholders
with user-selected values when applying a template.
Distribution
Section titled âDistributionâSame OCI pattern as Features (tarballs with custom media types, semver tagging). The namespace for Templates must be different from the namespace for Features.
devcontainerId Computation
Section titled âdevcontainerId ComputationâComputed from container labels:
- Serialize labels as sorted JSON (keys alphabetically, no whitespace).
- Compute SHA-256 of the UTF-8 encoded string.
- Base-32 encode the hash.
- Left-pad to 52 characters with
0.
The ID is deterministic across rebuilds and unique per Docker host.
JSON Schema
Section titled âJSON Schemaâ- Conforms to JSON Schema Draft 7.
- Permits comments (JSONC), disallows trailing commas.
- Base schema:
devContainer.base.schema.json. - Main schema:
devContainer.schema.json(references base + tool-specific schemas). - Source: devcontainers/spec on GitHub.
Official Reference Links
Section titled âOfficial Reference Linksâ| Resource | URL |
|---|---|
| Main Specification | https://containers.dev/implementors/spec/ |
| JSON Reference | https://containers.dev/implementors/json_reference/ |
| JSON Schema | https://containers.dev/implementors/json_schema/ |
| Features Overview | https://containers.dev/features/ |
| Features Spec (Implementors) | https://containers.dev/implementors/features/ |
| Features Distribution | https://containers.dev/implementors/features-distribution/ |
| Templates Overview | https://containers.dev/templates/ |
| Templates Spec (Implementors) | https://containers.dev/implementors/templates/ |
| Templates Distribution | https://containers.dev/implementors/templates-distribution/ |
| Supporting Tools | https://containers.dev/supporting |
| GitHub Repository | https://github.com/devcontainers/spec |