EXAMPLE 10
  • devcontainers
  • migration

Port a devcontainer.json

Turn an existing devcontainer.json into a devsandbox config.


The problem

Your repo already has a .devcontainer/devcontainer.json and you want to run it with devsandbox. Rewriting it from scratch risks losing something.

devsandboxes.toml uses the same property names in TOML, so most of the file moves over line by line. The differences: folder says which repo the sandbox is for, some properties are ignored, and compose setups become [services.*].

Let your agent set this up

Config

.devcontainer/devcontainer.json (before)
{
  "name": "web",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:22",
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {}
  },
  "forwardPorts": [3000],
  "containerEnv": { "NODE_ENV": "development" },
  "mounts": ["source=${localEnv:HOME}/.config/gh,target=/home/node/.config/gh,type=bind"],
  "remoteUser": "node",
  "postCreateCommand": "npm ci",
  "customizations": {
    "vscode": {
      "extensions": ["dbaeumer.vscode-eslint"],
      "settings": { "editor.formatOnSave": true }
    }
  }
}
devsandboxes.toml (after)
[sandbox.web]                      # the table key replaces `name`
folder = "../web"                  # the repo; devsandboxes.toml lives outside it
image = "mcr.microsoft.com/devcontainers/typescript-node:22"
forwardPorts = [3000]              # forwarded while the instance runs
containerEnv = { NODE_ENV = "development" }
mounts = ["source=${localEnv:HOME}/.config/gh,target=/home/node/.config/gh,type=bind"]
remoteUser = "node"
postCreateCommand = "npm ci"
# settings: ignored, keep them in the repo's .vscode/settings.json
customizations.vscode.extensions = ["dbaeumer.vscode-eslint"]

[sandbox.web.features]
"ghcr.io/devcontainers/features/github-cli:1" = {}

Try it

From the config dir:

TERMINAL
devsandbox ls                  # validates the config, no container needed
devsandbox run web
devsandbox exec -it web zsh

How it works

The devcontainer.json can stay in the repo; devsandbox never reads it.

Property mapping

devcontainer.json devsandboxes.toml notes
the file’s location folder required by run
name the table key name is ignored
image, features same Features: OCI references only
build.* build = { dockerfile, context, … } paths relative to the config dir
containerEnv, remoteEnv same containerEnv not ${…}-substituted
containerUser, remoteUser same
mounts same missing bind sources are created
workspaceFolder same default /workspaces/<folder basename>
workspaceMount folder ignored
init, privileged same
initializeCommand same runs on the host, in the config dir
onCreateCommand … postAttachCommand same tables run in order, not in parallel
customizations.vscode.extensions same
customizations.vscode.settings repo .vscode/settings.json ignored
forwardPorts same forwarded by the host daemon while the instance runs
appPort, portsAttributes devsandbox port web 3000 ignored
runArgs, capAdd, securityOpt none ignored
dockerComposeFile, service, runServices [services.*] + services error

Implemented, ignored, rejected

ls errors on unknown keys; run warns about ignored ones.

  • Implemented: image, build, features, workspaceFolder, mounts, containerEnv, remoteEnv, containerUser, remoteUser, init, privileged, the six lifecycle commands, customizations.vscode.extensions, forwardPorts (details).
  • Ignored: name, appPort, portsAttributes, otherPortsAttributes, runArgs, workspaceMount, overrideFeatureInstallOrder, updateRemoteUserUID, userEnvProbe, overrideCommand, shutdownAction, capAdd, securityOpt, hostRequirements, waitFor, secrets, other customizations.* (details).
  • Rejected: dockerComposeFile, service, runServices, and any unknown key.
  • Variables: as in devcontainers, plus ${configDir}, ${sharedVolumes}, ${instance}; substituted only in some keys (variables).

Coming from docker compose

The app container is the sandbox; each other compose service becomes a [services.<name>] (image, env, ports, command) that the sandbox lists in services and reaches by name as hostname. See private services per instance and one shared Postgres.

Agent instructions

Prompt for your coding agentPaste into Claude Code, Codex or any agent with a shell.

Port the devcontainer.json of my repo at <repo path> to a sandbox in my devsandbox devsandboxes.toml.

  1. Read the devsandbox-cli and config-toml-spec skills first (load them if they are installed, otherwise read them from https://github.com/Nemikolh/devsandboxes/tree/main/skills). Follow them over your own assumptions: unknown config keys are hard errors.
  2. Find my devsandbox config dir: the folder holding devsandboxes.toml, passed to devsandbox as -C <config dir>. If you cannot tell which one, ask me.
  3. Read <repo path>/.devcontainer/devcontainer.json and any Dockerfile or docker-compose.yml it references; do not modify them.
  4. Add a [sandbox.<sandbox name>] with folder pointing at <repo path> (relative to the config dir) and copy the implemented properties over; rebase build paths onto the config dir. Extend an existing template instead of repeating what it provides.
  5. Drop the properties the config-toml-spec lists as ignored and tell me what each did; turn compose services into [services.*] listed in services.
  6. Validate with devsandbox -C <config dir> ls and fix every error it reports before going on.
  7. Run devsandbox -C <config dir> run <sandbox name> and report any warning: lines, then devsandbox -C <config dir> exec <instance> <a command the repo needs>.
  8. Ask me before anything destructive: devsandbox rm, gc, rebuild --force, service rebuild, deleting files or branches.
fill in before sending Agent skills (opens in a new tab)

Source: site/src/content/examples/port-a-devcontainer.mdxEdit this page on GitHub(opens in a new tab)

MENU /
View on GitHub
EXAMPLES
All examplesEvery recipe on one page.Parallel coding agentsSeveral coding agents on one repo, fully isolated from one another.One shared PostgresOne development database for all your sandboxes and their instances.Private services per instanceEvery instance gets its own Postgres and Redis, so agents never touch each other's data.Shared package cachesNew sandboxes stop downloading the same packages again.ssh-agent and git pushAgents push over ssh with your host's keys, which never enter the container.Port forwarding on demandOpen a sandbox's dev server or database from your host, without restarting anything.Attach VS CodeOpen any instance in VS Code with one key.devcontainer FeaturesAdd Node, Rust or the GitHub CLI to any image, in TOML.Babysit pull requestsAn agent keeps your open PRs merged with their base, and pings you when it can't.Port a devcontainer.jsonTurn an existing devcontainer.json into a devsandbox config.