Create a Dev Container
The Visual Studio Code Dev Containers extension lets you use a Docker container as a full-featured development environment. It allows you to open any folder or repository inside a container and take advantage of Visual Studio Code's full feature set. A devcontainer.json
file in your project tells VS Code how to access (or create) a development container with a well-defined tool and runtime stack. This container can be used to run an application or to provide separate tools, libraries, or runtimes needed for working with a codebase.
Path to creating a dev container
In this document, we'll go through the steps for creating a development (dev) container in VS Code:
- Create a
devcontainer.json
, which describes how VS Code should start the container and what to do after it connects. - Make and persist changes to the dev container, such as installation of new software, through use of a Dockerfile.
- Configure multiple containers through Docker Compose.
- As you make changes, build your dev container to ensure changes take effect.
After any of the steps above, you'll have a fully functioning dev container, and you can either continue to the next step of this tutorial to add more features, or stop and begin working in the dev environment you currently have.
Note: The Dev Containers extension has a Dev Containers: Add Dev Container Configuration Files... command that lets you pick a pre-defined container configuration from a list. If you'd prefer to have a complete dev container immediately rather than building up the
devcontainer.json
and Dockerfile step-by-step, you can skip ahead to Automate dev container creation.
Create a devcontainer.json file
VS Code's container configuration is stored in a devcontainer.json file. This file is similar to the launch.json
file for debugging configurations, but is used for launching (or attaching to) your development container instead. The dev container configuration is either located under .devcontainer/devcontainer.json
or stored as a .devcontainer.json
file (note the dot-prefix) in the root of your project.
You can use an image as a starting point for your devcontainer.json
. An image is like a mini-disk drive with various tools and an operating system pre-installed. You can pull images from a container registry, which is a collection of repositories that store images. Here is a simple example devcontainer.json
that uses a pre-built TypeScript and Node.js VS Code Development Container image:
{
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18"
}
You can alter your configuration to do things such as:
- Install additional tools such as Git in the container.
- Automatically install extensions.
- Forward or publish additional ports.
- Set runtime arguments.
- Reuse or extend your existing Docker Compose setup.
- Add more Advanced container configuration.
For this example, if you'd like to install the Code Spell Checker extension into your container and automatically forward port 3000, your devcontainer.json
would look like:
{
"image": "mcr.microsoft.com/devcontainers/typescript-node",
"customizations": {
"vscode": {
"extensions": ["streetsidesoftware.code-spell-checker"]
}
},
"forwardPorts": [3000]
}
Note: Additional configuration will already be added to the container based on what's in the base image. For example, we add the
streetsidesoftware.code-spell-checker
extension above, and the container will also include"dbaeumer.vscode-eslint"
as that's part ofmcr.microsoft.com/devcontainers/typescript-node
. This happens automatically when pre-building using devcontainer.json, which you may read more about in the pre-build section.
With the above devcontainer.json
, your dev container is functional, and you can connect to and start developing within it. Try it out with the Dev Containers: Reopen in Container command:
After running this command, when VS Code restarts, you're now within a Node.js and TypeScript dev container with port 3000 forwarded and the ESLint extension installed. Once you're connected, notice the green remote indicator on the left of the Status bar to show you are connected to your dev container:
Additional dev container scenarios
Through a devcontainer.json
file, you can:
- Spin up a stand-alone container to isolate your toolchain or speed up setup.
- Work with a container deployed application defined by an image, Dockerfile, or Docker Compose.
- Use Docker or Kubernetes from inside a dev container to build and deploy your app.
If devcontainer.json
's supported workflows do not meet your needs, you can also attach to an already running container instead.
Tip: Want to use a remote Docker host? See the Develop on a remote Docker host article for details on setup.
Install additional software
You may want to install additional software in your dev container. Once VS Code is connected to the container, you can open a VS Code terminal and execute any command against the OS inside the container. This allows you to install new command-line utilities and spin up databases or application services from inside the Linux container.
Most container images are based on Debian or Ubuntu, where the apt
or apt-get
command is used to install new packages. You can learn more about the command in Ubuntu's documentation. Alpine images include a similar apk
command while CentOS / RHEL / Oracle SE / Fedora images use yum
or more recently dnf
.
Documentation for the software you want to install will usually provide specific instructions, but you may not need to prefix commands with sudo
if you are running as root in the container.
For example:
# If running as root
apt-get update
apt-get install <package>
If you are running as root, you can install software as long as sudo
is configured in your container. All predefined containers have sudo
set up, but the Add a non-root user to a container article can help you set this up for your own containers. Regardless, if you install and configure sudo
, you'll be able to use it when running as any user including root.
# If sudo is installed and configured
sudo apt-get update
sudo apt-get install <package>
Let's say you want to install Git. You could run the following commands in the integrated terminal in VS Code:
# If sudo is installed and configured
sudo apt-get update
# Install Git
sudo apt-get install git
You may also use the "features"
property in the devcontainer.json
to install tools and languages from a pre-defined set of Features or even your own.
For example, you could install the latest version of the Azure CLI with the following:
"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {
"version": "latest"
}
}
See the Dev Container Features specification for more details.
Rebuild
When editing the contents of the .devcontainer
folder, you'll need to rebuild for changes to take effect. Use the Dev Containers: Rebuild Container command for your container to update.
However, if you rebuild the container, you will have to reinstall anything you've installed manually. To avoid this problem, you can use the postCreateCommand
property in devcontainer.json
or a custom Dockerfile
.
A custom Dockerfile
will benefit from Docker's build cache and result in faster rebuilds than postCreateCommand
. However, the Dockerfile
runs before the dev container is created and the workspace folder is mounted and therefore does not have access to the files in the workspace folder. A Dockerfile
is most suitable for installing packages and tools independent of your workspace files.
The postCreateCommand
actions are run once the container is created, so you can also use the property to run commands like npm install
or to execute a shell script in your source tree (if you have mounted it).
"postCreateCommand": "bash scripts/install-dependencies.sh"
You can also use an interactive bash shell so that your .bashrc
is picked up, automatically customizing your shell for your environment:
"postCreateCommand": "bash -i scripts/install-dependencies.sh"
Tools like NVM won't work without using -i
to put the shell in interactive mode:
"postCreateCommand": "bash -i -c 'nvm install --lts'"
The command needs to exit or the container won't start. For instance, if you add an application start to postCreateCommand
, the command wouldn't exit.
There is also a postStartCommand
that executes every time the container starts. The parameters behave exactly like postCreateCommand
, but the commands execute on start rather than create.
Rather than referencing an image directly in devcontainer.json
or installing software via the postCreateCommand
or postStartCommand
, an even more efficient practice is to use a Dockerfile.
Dockerfile
A Dockerfile will also live in the .devcontainer
folder. You can replace the image
property in devcontainer.json
with dockerfile
:
{
"build": { "dockerfile": "Dockerfile" },
"customizations": {
"vscode": {
"extensions": ["dbaeumer.vscode-eslint"]
}
},
"forwardPorts": [3000]
}
When you make changes like installing new software, changes made in the Dockerfile will persist even upon a rebuild of the dev container.
In your Dockerfile, use FROM
to designate the image, and the RUN
instruction to install any software. You can use &&
to string together multiple commands.
FROM mcr.microsoft.com/devcontainers/javascript-node:0-18
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install git
Note: The
DEBIAN_FRONTEND
export avoids warnings when you go on to work with your container.
Automate dev container creation
Rather than creating a .devcontainer
by hand, selecting the Dev Containers: Add Dev Container Configuration Files... command from the Command Palette (F1
) will add the needed files to your project as a starting point, which you can further customize for your needs.
The command lets you pick a pre-defined container configuration from a list based on your folder's contents:
The predefined container configurations you can pick from come from our first-party and community index, which is part of the Dev Container Specification. We host a set of Templates as part of the spec in the devcontainers/templates repository. You can browse the src
folder of that repository to see the contents of each Template.
At the end of using Dev Containers: Add Dev Container Configuration Files..., you'll be shown the list of available features, which are tools and languages you can easily drop into your dev container. Dev Containers: Configure Container Features allows you to update an existing configuration.
You can also reuse an existing Dockerfile:
Now that you have a devcontainer.json
and Dockerfile, let's see the general process for editing container configuration files.
Full configuration edit loop
Editing your container configuration is easy. Since rebuilding a container will "reset" the container to its starting contents (with the exception of your local source code), VS Code does not automatically rebuild if you edit a container configuration file (devcontainer.json
, Dockerfile
, and docker-compose.yml
). Instead, there are several commands that can be used to make editing your configuration easier.
Here is the typical edit loop using these commands:
- Start with Dev Containers: Add Dev Container Configuration Files... in the Command Palette (
F1
). - Edit the contents of the
.devcontainer
folder as required. - Try it with Dev Containers: Reopen in Container.
- If you see an error, select Open Folder Locally in the dialog that appears.
- After the window reloads, a copy of the build log will appear in the console so you can investigate the problem. Edit the contents of the
.devcontainer
folder as required. (You can also use the Dev Containers: Show Container Log command to see the log again if you close it.) - Run Dev Containers: Rebuild and Reopen in Container and jump to step 4 if needed.
If you already have a successful build, you can still edit the contents of the .devcontainer
folder as required when connected to the container and then select Dev Containers: Rebuild Container in the Command Palette (F1
) so the changes take effect.
You can also iterate on your container when using the Dev Containers: Clone Repository in Container Volume command.
- Start with Dev Containers: Clone Repository in Container Volume in the Command Palette (
F1
). If the repository you enter does not have adevcontainer.json
in it, you'll be asked to select a starting point. - Edit the contents of the
.devcontainer
folder as required. - Try it with Dev Containers: Rebuild Container.
- If you see an error, select Open in Recovery Container in the dialog that appears.
- Edit the contents of the
.devcontainer
folder as required in this "recovery container." - Use Dev Containers: Reopen in Container and jump to step 4 if you still hit problems.
Use Docker Compose
In some cases, a single container environment isn't sufficient. Let's say you'd like to add another complex component to your configuration, like a database. You could attempt to add it to the Dockerfile directly, or you could add it through an additional container. Fortunately, Dev Containers supports Docker Compose managed multi-container configurations.
You can either:
- Work with a service defined in an existing, unmodified
docker-compose.yml
. - Create a new
docker-compose.yml
(or make a copy of an existing one) that you use to develop a service. - Extend your existing Docker Compose configuration to develop the service.
- Use separate VS Code windows to work with multiple Docker Compose-defined services at once.
Note: When using Alpine Linux containers, some extensions may not work due to
glibc
dependencies in native code inside the extension.
VS Code can be configured to automatically start any needed containers for a particular service in a Docker Compose file. If you've already started the configured containers using the command line, VS Code will attach to the running service you've specified instead. This gives your multi-container workflow the same quick setup advantages described for the Docker image and Dockerfile workflows above, while still allowing you to use the command line if you prefer.
To get started quickly, open the folder you want to work with in VS Code and run the Dev Containers: Add Dev Container Configuration Files... command in the Command Palette (F1
).
You'll be prompted to pick a pre-defined container configuration from our first-party and community index in a filterable list sorted based on your folder's contents. From the VS Code UI, you may select one of the following Templates as a starting point for Docker Compose:
- Existing Docker Compose - Includes a set of files that you can drop into an existing project that will reuse a
docker-compose.yml
file in the root of your project. - Node.js & MongoDB - A Node.js container that connects to a MongoDB database in a different container.
- Python & PostgreSQL - A Python container that connects to PostgreSQL in a different container.
- Docker-Outside-of-Docker Compose - Includes the Docker CLI and illustrates how you can use it to access your local Docker install from inside a dev container by volume mounting the Docker Unix socket.
After you make your selection, VS Code will add the appropriate .devcontainer/devcontainer.json
(or .devcontainer.json
) file to the folder.
You can also create your configuration manually. To reuse a Docker Compose file unmodified, you can use the dockerComposeFile
and service
properties in .devcontainer/devcontainer.json
.
For example:
{
"name": "[Optional] Your project name here",
"dockerComposeFile": "../docker-compose.yml",
"service": "the-name-of-the-service-you-want-to-work-with-in-vscode",
"workspaceFolder": "/default/workspace/path/in/container/to/open",
"shutdownAction": "stopCompose"
}