Published on

Dockerize your Node app

4 min read


Hey, welcome back. This article is part of the Dockerize series, make sure to checkout the Introduction where I go over some concepts we are going to use.

Today we'll dockerize our Node application, very similar to how we dockerized our React app in the last part by taking advantage of builder pattern with multi stage builds!

I've also made a video, if you'd like to follow along

Project setup

I've initialized a simple express app

├── node_modules
├── index.js
├── package.json
└── yarn.lock
const express = require('express');

const app = express();
const PORT = process.env.PORT || 4000;

app.get('/', (request, response) => {
    message: 'Hello Docker!',

app.listen(PORT, () => {
  console.log(`Server is up on localhost:${PORT}`);

I've also setup esbuild to bundle our project.

"build": "esbuild --bundle src/index.js --outfile=build/app.js --minify --platform=node"

For more details, you can checkout my previous article Blazing fast TypeScript with Webpack and ESBuild.

For development

Let's start by adding a Dockerfile

FROM node:14-alpine AS development
ENV NODE_ENV development
# Add a work directory
# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .
RUN yarn install
# Copy app files
COPY . .
# Expose port
# Start the app
CMD [ "yarn", "start" ]

Let's create a Here we'll also mount our code in a volume so that we can sync our changes with the container while developing.

version: '3.8'

    container_name: app-dev
    image: app-dev
      context: .
      target: development
      - ./src:/app/src
      - 4000:4000

Let's update our package.json scripts

"dev": "docker-compose -f up"

we can use the -d flag to run in daemon mode

Let's start developing!

yarn dev

Great, our dev server is up!

Attaching to app-dev
app-dev  | yarn run v1.22.5
app-dev  | $ nodemon src/index.js
app-dev  | [nodemon] to restart at any time, enter `rs`
app-dev  | [nodemon] watching path(s): *.*
app-dev  | [nodemon] starting `node src/index.js`
app-dev  | Server is up on localhost:4000

For production

FROM node:14-alpine AS builder
ENV NODE_ENV production
# Add a work directory
# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .
RUN yarn install --production
# Copy app files
COPY . .
# Build
CMD yarn build

FROM node:14-alpine AS production
# Copy built assets/bundle from the builder
COPY --from=builder /app/build .
# Start the app
CMD node app.js

Let's add a for production

version: '3.8'

    container_name: app-prod
    image: app-prod
      context: .
      target: production
docker-compose -f build

let's start our production container on port 80 with the name react-app

docker run -p 80:4000 --name node-app app-prod

Next steps

With that, we should be able to take advantage of docker in our workflow and deploy our production images faster to any platform of our choice.

Feel free to reach out to me on Twitter if you face any issues.

© 2023 Karan Pratap Singh