Docker and Apple containersNightly
Run a workroom in a Docker or Apple container on your Mac, made from your repository's devcontainer.json, with its ports forwarded to localhost.
This page describes a feature that is only in Nightly builds so far.
A container workroom runs in a container on your Mac instead of in a git worktree. Its terminals, files and coding agents live inside the container, so what you install or run there stays out of your Mac. For what remote workrooms are, see Remote workrooms.
A container workroom has a fresh host of its own, a fresh clone of your repository, and the same panes and inspector as other remote workrooms. Its host runs on your Mac and needs no cloud account. To use a Linux server you already have, choose an SSH host.
Important
Container workrooms made by an earlier Nightly, before containers were made from devcontainer.json, can't be opened by this one. Their status, Changes panel and terminals say the workroom was set up by an older Workroom Nightly. Delete each one and create it again. Deleting it destroys the container, with any work in it you haven't pushed.
Requirements
For either runtime:
- Your project's
originmust be on github.com, and its base branch must be onorigin. See Remote workrooms. - The GitHub CLI,
gh, must be signed in on your Mac. Rungh auth loginif it is not. A container gets its GitHub access from your Mac'sgh, so the choice saysrun gh auth loginwhile you are signed out.
For Docker:
- Docker Desktop, OrbStack or Colima, with the
dockercommand installed. Workroom looks for it at/usr/local/bin/docker,/opt/homebrew/bin/docker, and insideDocker.app. - Docker must be running. If it is not, the create stops with
Docker didn't answer. Start it, then try again.
For Apple Container:
- An Apple silicon Mac running macOS 26 or later.
- Apple's
containertool, from github.com/apple/container, at/usr/local/bin/containeror/opt/homebrew/bin/container. - Its system service running. If it is not, the create stops and tells you to run
container system start.
A runtime that does not meet these is dimmed in the New Workroom menu, with the reason beside its name: not installed, run gh auth login, needs Apple silicon or needs macOS 26.
Create a container workroom
- Click the + on a project, or right-click the project and choose New Workroom.
- Under Local containers, choose Docker or Apple Container.
- Watch the checklist in the pane. When it finishes, click Done.
The checklist runs Check repository, Read devcontainer.json, Run initializeCommand, Pull image, Build image, Start container, Connect, Clone repository, Check out branch, Copy local files, then each lifecycle command your devcontainer.json has, and Run setup script. A step your project doesn't need is skipped.
The first create from an image downloads it, and the Pull image row shows how far the download has got. Later creates reuse it, and that row says Image already downloaded. If the download fails, the message says whether the registry refused it or your network failed.
Apple's runtime gives each container a VM of its own, and its default is too small for a compiler or an agent. So Workroom gives each Apple container half of your Mac's cores and a quarter of its memory, between 2 GB and 8 GB. Docker's containers share Docker's own VM.
Your dev container
Workroom makes the container from your repository's dev container file, .devcontainer/devcontainer.json or .devcontainer.json, the same file VS Code, Codespaces and DevPod read. It reads the file from the commit the new workroom starts from, on origin, so a change you haven't pushed to a file already there isn't used. When that commit has no dev container file, the one in your project's folder is used, with the Dockerfile and build context beside it, so you can try a new one before you push it. Comments and trailing commas are allowed.
Workroom uses these keys:
image, orbuildwith itsdockerfile,context,argsandtarget.features, fetched from their registry and installed in the order the spec gives them.containerEnv,remoteEnv,remoteUserandcontainerUser.mountsandcapAdd, and on DockerrunArgs,privilegedandsecurityOpt.workspaceFolder: where the workroom's clone goes,/workspaces/<repository>if you don't set it.forwardPortsandportsAttributes. See Port forwarding.- The lifecycle commands, below.
A key Workroom can't honour doesn't stop the create: the Read devcontainer.json row warns, naming each one and why. That covers workspaceMount (each workroom clones into workspaceFolder instead), appPort, hostRequirements, postAttachCommand, runArgs and the other Docker settings on Apple's runtime, and any key Workroom doesn't know. A file that describes Docker Compose services can't be used: the create stops and offers Continue With Default Image.
A Dockerfile on its own, with no devcontainer.json naming it, is ignored, as the spec has it.
Approve it first
Your devcontainer.json decides what the container mounts from your Mac and what runs there, and its initializeCommand runs on your Mac itself, so Workroom uses it only after you have approved its exact contents on this Mac, as it does for setup scripts. The first create that would use a new file, or one that changed since you approved it, stops and shows it to you, with Approve, Continue With Default Image… and Cancel Creation. Continuing creates the workroom on the default image and approves nothing, so the next create asks again.
An approval covers the file's own contents only. The Dockerfile it builds, and the features it installs, aren't covered. A feature can itself ask for folders from your Mac to be mounted in the container, or for the container to be privileged, and a new release of the feature can add that without asking you again. Use features you trust, as you would any code your repository runs.
Lifecycle commands
They run as the container's user:
initializeCommandruns on your Mac, in your project, before the image is built.- After the clone and Copy local files:
onCreateCommand,updateContentCommand,postCreateCommandandpostStartCommand, in that order, each as a row of its own. - Run setup script comes last, so
scripts/workroom_setupsees the container as VS Code would leave it, with anythingpostStartCommandstarted already running. postStartCommandruns again each time the container starts, on the first connect after it. A terminal you open meanwhile says it is waiting for it, and attaches once it is done. Updating Workroom doesn't start the container again, so it doesn't rerun.
remoteEnv reaches every lifecycle command, the setup script and your terminals. The spec's variables, such as ${containerWorkspaceFolder} and ${localWorkspaceFolderBasename}, are filled in in the commands, workspaceFolder, mounts and environments.
Without a devcontainer.json
A repository with no dev container file gets Workroom's default image, the devcontainers project's Ubuntu base, run as its vscode user, who has passwordless sudo. Nothing is added to it.
To use another image, add a devcontainer.json to your repository that names it with image, or builds it from a Dockerfile with build. A Dockerfile with no devcontainer.json naming it isn't used. Whatever the image, it needs git and a shell. If it lacks either, the create fails and names the missing one.
When the file changes
A change to devcontainer.json, or to the Dockerfile it builds, applies to workrooms you create after it. The Details pane shows what a container was made from under Made From, and a note when the repository's devcontainer.json has changed since, or has been added or removed. A change to only the Dockerfile shows no note. To pick up a change, create a new workroom.
Working in a container
- The workroom's folder is a fresh clone inside the container. Only pushed work reaches it. Changes that are only on your Mac do not appear until you push them.
- Git inside the container asks your Mac's
ghfor GitHub credentials, while Workroom is open. Anything running in the container can ask, so it has the same GitHub access thatghhas on your Mac. - A server you run in the container listens inside it, where your browser cannot reach it. Workroom forwards ports to
localhostfor you. See Port forwarding. - Your setup and teardown scripts run in the container, with
WORKROOM_HOSTset todockerorapple. See Remote workrooms. - The image's own entrypoint and command don't run: the container runs Workroom's daemon in their place.
Starting and stopping
Workroom creates the container, starts it when you open its workroom and it isn't running, and stops and removes it when you delete the workroom.
Terminals in a container workroom reattach after the container comes back. See Reconnecting.
Delete the workroom
Deleting the workroom destroys its container and everything in it, including changes and commits that were not pushed, and the volumes made for it alone, such as docker-in-docker's. A volume your devcontainer.json names without ${devcontainerId} is shared by its workrooms and kept. See Delete a remote workroom.
A container belongs to the build of Workroom that made it. Release and Nightly cannot delete each other's containers.