Developing in Containers with Visual Studio Code

Visual Studio Code now offers the ability to use a docker container as a fully fledged development environment with the introduction of the Remote Containers extension.

Workspace files are made accessible from inside a container which can also host the tools relevant to the development environment, leaving VS Code acting as a remote UI to enable a ‘local quality’ development experience:

Container Architecture

The obvious benefit here is the ability to very rapidly spin up a development environment through the use of pre-existing containers which already provide all required components.

Starting Up

First thing to do is create the config files that will tell VS Code how to configure the environment; this can be done by executing ‘Add Development Container Configuration Files’ (Ctrl + Shift + P):

This will create devcontainer.json and Dockerfile files under .devcontainer within the workspace.

The Dockerfile defines the container that Code will create and then connect to for use as a development environment. A bare bones Dockerfile for use with a Node app may look like this:

FROM node:slim
USER node

devcontainer.json defines how VS Code should work with a remote container. A simple example below shows how to reference the Dockerfile:

// For format details, see For config options, see the README at:
	"name": "TriggerService",
	"build": {
		"dockerfile": "Dockerfile",

	"settings": { 
		"": "/bin/bash"

	"extensions": [

	"remoteUser": "node"

With both of these files in place, VS Code will prompt to re-open in the container environment (or use the command palette to execute ‘Reopen in Container’):

Dev Container Progress Notification

Once started up, an indicator in the bottom left shows that VS Code is currently connected to a container:

Create a Simple App

At this point VS Code is now connected to the node:slim container as configured in the Dockerfile.

Because this image provides everything needed to start developing a Node application, we can start by using npm to install Express:

npm init -y
npm install express

Then create index.js under the src folder:

const express = require( "express" );
const app = express();
const port = 8080;

// define a route handler for the default home page
app.get( "/", ( req, res ) => {
    res.send( "Hello world!" );
} );

// start the Express server
app.listen( port, () => {
    console.log( `server started at http://localhost:${ port }` );
} );

Next we need to update the package.json file to set the main entry point and start command:

  "name": "test-app",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "start": "node .",
    "test": "echo \"Error: no test specified\" && exit 1"
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"

Now executing the following command from the terminal will start up the application inside the container:

npm run start

The key thing to note here is that we stood up this simple Node app without ever having to actually install Node on our host system; everything was pulled down via the node:slim docker image.

At this point the application is exposed on port 8080, so can be accessed at http://localhost:8080.

What’s Next?

We have only covered enough here to get up and running, barely scratching the surface of what can be done with remote containers.

Next up, debugging from inside a container, and using docker compose to handle spinning up multiple containers.