Quick and dirty Docker development environment for Node.js apps

Photo by Jefferson Santos on Unsplash

Pre-requisites

Files

Usage

Start the environment.

docker-compose up -d

Attach to the container in VSCode.

Enjoy! :)

When done, stop the environment.

docker-compose stop

Why?

I wrote an article on the benefits of using a Dockerized development environment. Check it out here:

What is this good for?

A Node.js app can be:

  • an Express backend (eg. a REST API)

It is up to you what you make in this environment. I usually do React frontends.

Tips

When you are attached to the container in VSCode, the IDE’s terminal opens a terminal session inside the container. Here you can execute commands directly inside your container without the need to attach to it from another external terminal like PowerShell.

You can reduce the time spent starting and stopping the environment by shortening your Docker commands with Bash functions. If you have multiple concurrent projects, this will save you time and annoyance. I also wrote an article on how to do this, read it here:

After you opened the dev container once, you can return to it from the “Open recent…” (Ctrl+R) command of VSCode. You don’t have to always do the “Attach to running container…” command.

You can extend this bare bones development environment with many different functionalities. I listed my suggestions here.

If you would like to install packages in the container, the best way is to create a Dockerfile, define the install commands inside and change the image property in the yml to build with the correct reference to the build context. Here is an example for ffmpeg and the Vercel CLI:

FROM node:14.5.0-alpine
RUN apk add ffmpeg
RUN npm i -g vercel

You could also install Git to get access to the version control tools inside VSCode while you are attached to the container. However, if you want to do version control efficiently inside the container, you will need to set up SSH and configure Git to be able to push your code. It is possible, but I am not a fan because it makes the setup more complex. I do version control on the host system in a separate VSCode window with the IDE’s built-in Git tools and the Git Graph extension.

Explained, line-by-line

PROJECT_NAME=my-project
PORT=3000

Docker-compose can fetch the environment variables from a local .env file. The purpose of this is to avoid repetition in the docker-compose.yml.

image: node:14.5.0-alpine

I use the Alpine version of the Node image simply because it is small (40 MB compared to the :latest 344 MB). I also use fixed versions to avoid the image upgrading itself and breaking something when I'm in a rush. This way I can upgrade the image when I have the time.

working_dir: /usr/src/${PROJECT_NAME}

You can use any working directory you want inside the container, I just use /usr/src to avoid name collisions in the root of the filesystem. It also helps me differentiate the projects in VSCode's "Open recent..." menu — back when I used /app or /code everywhere, I didn't know which project's folder I'm about to open.

env_file:
- .env

The environment variables defined in .env will be available inside the container. This is where I put my config options, passwords and secret keys for the app.

ports:
- ${PORT}:${PORT}

There is a high chance I’m building a web app or a REST API, so I map a port of the container to the same port of the host system to be able to access my app or service in the browser.

volumes:
- /usr/src/${PROJECT_NAME}/node_modules
- .:/usr/src/${PROJECT_NAME}

I am mapping the project directory to the container’s working directory so that the edits I make in the container propagate to the host system where I do my version control. I don’t want the content of node_modules leaking into my host system however, so I defined that folder as a volume on its own. Otherwise the npm installs would be noticeably slower because the files need to be copied from the container to the host.

entrypoint: tail -F /dev/null

If I would start the container without this entrypoint, it would just exit and I would not be able to attach to it. This command makes the container run indefinitely.

For more advanced devcontainer options visit VSCode’s Developing inside a Container article.

Thank you for reading to the end and have a wonderful day :)

React Developer, frontend enthusiast, student