How To Dockerize a Typescript Node.js App.

Rainer Regan
6 min readApr 24, 2024

Hi, we are back with the Dockerize series here. Docker is one of the most amazing tools to make your app development much easier and quicker. Moreover, Docker will help us to shorten the path needed to deploy our app.

Docker is a tool that will allow developers to containerize their apps and run them easily across different ecosystems without any worries of incompatibility. Docker runs your app’s image into a container that can be run on any OS that supports the Docker daemon.

What is Node.js

If you are searching for this title, you may or may not have known what Node Js is, but if you came across this article accidentally, don’t worry, I will explain Node.js as briefly as possible.

Node.js is one of the most popular Javascript server runtime environments. You may often hear that Javascript is mainly used in front-end development for DOM manipulation, but this is not the case. Node.js will allow us to run Javascript from the server side.

Why Typescript?

Typescript is a more advanced version of the Javascript language. Typescript allows developers to use strictly typed Javascript code to ensure the scalability and maintainability of the code. With Typescript, you don't need to worry about Javascript syntax inconsistencies.

Prerequisites

Now, we will start this tutorial, but before advancing, I want to make sure that you already have installed these apps on your systems:

  • Node.js (run node -v on your terminal to check if Node is installed). You can install Node.js from their official website here.
  • Docker
  • Git (optional). If you want to use a demo project, you can install Git on your system to clone it directly.
  • A Typescript Node Js Project (optional). I will show you how to create a simple Node app with the Express framework, or you can clone my demo repository.
  • VS Code or any code editor.

Now, let's begin.

Step 1 — Create a Typescript Node.js App (Optional)

Clone Demo App

In this step, I will show you how to create a simple Node js app, if you already have a project, you can use your own project or you can use my demo project by cloning it from my GitHub.

git clone https://github.com/rainerregan/node-docker-demo.git

Then, you need to change the directory to the project and install all of its dependencies.

cd node-docker-demo
npm install

Now, you can try to run the app

npm run dev

Create Node app from scratch

To make this tutorial focus on the dockerize process, I will not try to cover all the steps of creating a Node JS app using Typescript from scratch, but you can read my other article on creating the Node JS app using Typescript from scratch here.

Step 2 — Create a Dockerfile

Before creating a container to run our app, we need to create a Docker image of our app. Image is a bundle of our app with all of its dependencies, so we can run this into a container that can be deployed on any Docker environment.

To create a Docker image, we need a file called ‘Dockerfile’. A Dockerfile is a set of commands or instructions for building a Docker image. These commands define the steps required to set up the environment and configure the application inside the container.

To create a Dockerfile, we can create a new file called ‘Dockerfile’ on our root folder, and yes, without any extensions.

node-docker-demo/
├── Dockerfile <<<--- Create this
├── node_modules/
├── package-lock.json
├── package.json
└── src/

Then open the file and type this command. I will try to explain the command to be as clear as possible.

# Set the base image from Docker repository to build our app. In this case we want to use node image to run our node app
FROM node:18.16.0-alpine as base

# Then, we need to copy our package.json and .env file into the image root folder.
COPY package.json ./

# Then, we need to install the dependencies inside the base image
RUN yarn install

# After installing the dependencies, we need to copy the src folder from our local file into the base image
COPY src ./src

# Copy tsconfig.json to base image too
COPY tsconfig.json ./tsconfig.json

# Then, run the build command, this will compile the ts files into javascript files
RUN npm run build

# After using base image for build process, we can create another image for the production build
# Start production image build, we will use the same node image
FROM node:18.16.0-alpine

# Copy node modules and build directory from base image to new image
COPY --from=base ./node_modules ./node_modules
COPY --from=base ./package.json ./package.json
COPY --from=base /dist /dist

# Expose port 3000, and start the app.
EXPOSE 3000
CMD ["npm", "run", "start"]

After entering this command on the Dockerfile, we need to create a docker ignore file to prevent directories and files from being copied into the image.

Create a ‘.dockerignore’ file on the root, and type this:

./node_modules
Dockerfile
.dockerignore
docker-compose.yml

We want all files and folders from this list to be ignored in the image-building process.

Step 3 — Using Docker Compose

In this tutorial, I will use Docker Compose to make it easier to build and run the container. Without Docker Compose, we can still build and run the app, but it will take a longer command to type, and I want to keep it as simple as possible because, in the development phase, you will need to rebuild the image regularly.

First, create a new file on the root folder named ‘docker-compose.yml’. In this file, we will define the requirements for the container.

# We will use Docker compose v3.9
version: '3.9'

services:
api:
image: node-docker-demo:latest # Specify your custom Node.js image name and tag
build: .
command: npm run start
ports:
- '4000:3000' # Specify the exposed port, we will need this to access the app from local machine
volumes:
- ./api:/app

Docker compose will handle the building and running process, so you can use simple commands to run or build the image.

With this step done, you have finished the Dockerizing preparation, now you can utilize Docker Compose to build or build & run the app.

Step 4 — Running The App Using Docker Compose

After setting up the Dockerfile and Docker Compose, we can try to run the app using Docker Compose.

By running this command, Docker will automatically build your image and run the container.

docker compose up

Then, you will see the output like this

host@computer % docker compose up         

[+] Running 1/1
! api Warning 4.2s
[+] Building 15.2s (14/14) FINISHED docker:desktop-linux
=> [api internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [api internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.14kB 0.0s
=> [api internal] load metadata for docker.io/library/node:18.16.0-alpine 1.8s
=> [api internal] load build context 0.0s
=> => transferring context: 629B 0.0s
=> CACHED [api base 1/6] FROM docker.io/library/node:18.16.0-alpine@sha256:9036ddb8252ba7089c2 0.0s
=> [api base 2/6] COPY package.json ./ 0.1s
=> [api base 3/6] RUN yarn install 11.9s
=> [api base 4/6] COPY src ./src 0.0s
=> [api base 5/6] COPY tsconfig.json ./tsconfig.json 0.0s
=> [api base 6/6] RUN npm run build 1.1s
=> CACHED [api stage-1 2/4] COPY --from=base ./node_modules ./node_modules 0.0s
=> [api stage-1 3/4] COPY --from=base ./package.json ./package.json 0.0s
=> [api stage-1 4/4] COPY --from=base /dist /dist 0.0s
=> [api] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:10fc77d29b7cbeed026862277ebf9093386cd7000c349ea97c07a16f49c78e86 0.0s
=> => naming to docker.io/library/node-docker-demo:latest 0.0s
[+] Running 1/1
✔ Container node-docker-demo-api-1 Created 0.0s
Attaching to api-1
api-1 |
api-1 | > docker-demo@1.0.0 start
api-1 | > NODE_ENV=production node dist/index
api-1 |
api-1 | Server is running on http://localhost:3000

We can see that the server is now running on port 3000, but remember, 3000 is the port that we set for the app, since the app is running inside an isolated container, we should access the app via the bridge port that we have set on the docker-compose.yml

...
ports:
- '4000:3000' # Specify the exposed port, we will need this to access the app from local machine
....

In this file, we have set the exposed port to be 4000. So, we can visit localhost:4000 to see if our app is running perfectly.

You can see that our app is now running on port 4000, Yay~.

Conclusion

In this article, you have learned how to utilize Docker and Docker Compose to create a Docker image that will then be used as a container to run a Nodejs App. You also learn how to create a Dockerfile to define the steps used in building the image.

Thank you and happy coding!

--

--

Rainer Regan
Rainer Regan

Written by Rainer Regan

Hi, I'm a software engineer, I write articles to share my experiences in software engineering. Founder of Exacode Systems. https://exacode.io

Responses (1)