While NodeJS provides a simple CLI to run apps, sometimes this isn’t enough.

If you want to back your app up with a database or orchestrate some other configuration, it can be useful to run your Node app through a Docker container. This is how you’d set one up.

In a subsequent post, we will be adding mysql to the docker network. I’ve also wanted to mount my app into docker in order to reflect my changes to the app right away. Because of this, we’ll also be using docker compose.

To create a better developing environment, we’re also gonna make use of nodemon, transferring and updating our app after every save.

Note: You can view the full project and code on Github.


Say we have initialized npm in a directory, now containing of the following files:

- app.js
- package.json

Our app sets up a basic http-server with the help of expressJS:


const express = require("express")

const app = express()

app.get("/", (req, res) => {
  res.send("Hello World")

app.listen(3000, () => {
  console.log("Started App")

The package.json only contains the two dependencies (express and nodemon) as well as the start script:

"start": "nodemon app.js"

Note: Using Windows we have to add the --legacy-watch flag, so that nodemon picks up on the changes.

"start": "nodemon app.js --legacy-watch"

  "name": "nodejs-docker",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon app.js --legacy-watch"
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "nodemon": "^2.0.12"

The node docker image

To create our own docker image executing the steps necessary to run the app, we create a Dockerfile right within the base directory.

FROM node:14-slim
COPY package.json /app/
RUN npm install
CMD ["npm","start"]

FROM node:14-slim defines our starting point, which is the official node image provided by the docker registry.

After that we’re using WORKDIR /app to create a working directory within our docker container. With **COPY package.json /app/ we’re taking our package.json file into the virtual directory.

To install the dependencies within docker, we use RUN npm install.

Finally with CMD ["npm","start"] we’re running our start-script that we’ve defined in our package.json.

Docker compose


version: "3.9"

    build: .
      - "3000:3000"
      - .:/app

The docker-compose file is very simple. First, we define the version. After that we’re setting up our only service, in this case named web. Using build we indicate to docker-compose that the corresponding dockerfile is in the same directory.

Note that in app.js the server is listening on port 3000, so we’re going to map the port to the same using ports.

Finally, we have to mount our files (in this case only app.js) as a volume into our docker-working-directory /app. This results in our changes to app.js being directly mirrored in the docker environment, causing nodemon to pick up on the changes and restart the server.

In the terminal we now run:

docker compose up

We should now see the console.log of “Started app” by our app.js.

Visiting localhost:3000 we can now access the running app. After changes to app.js, nodemon is restarting the server.

Source on Github: https://github.com/HooK2000/nodejs-docker-express/tree/nodejs

The creation of this post was made possible by coffee.
Buy me a coffee