DEV Community

Cover image for How to Dockerize and Deploy Express.js APIs
Jonas Scholz
Jonas Scholz Subscriber

Posted on

How to Dockerize and Deploy Express.js APIs

If you're just here to copy and paste, here's the final Dockerfile that will produce an image for your Express.js app:

FROM node:22.10.0-alpine.3.19

LABEL maintainer="jonas@sliplane.io"

WORKDIR /app

COPY package* ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["node", "index.js"]
Enter fullscreen mode Exit fullscreen mode

And here's the .dockerignore file you should use:

node_modules
npm-debug.log
Enter fullscreen mode Exit fullscreen mode

To build and run the image, use these commands:

docker build -t express-app .
docker run -p 3000:3000 express-app
Enter fullscreen mode Exit fullscreen mode

Not just here to copy and paste? Let's go over what's happening in the Dockerfile!

let's do this

The Setup

For this tutorial, I assume you have an Express.js project set up. Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. If you have a different setup, you might need to adjust the Dockerfile accordingly.

Typically, you'd run npm install and then node index.js to work locally. For deployment, we'll use a similar approach but within a Docker container.

Let's dive into the details of the Dockerfile.

The Dockerfile

FROM node:22.10.0-alpine.3.19

LABEL maintainer="jonas@sliplane.io"

WORKDIR /app

COPY package* ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["node", "index.js"]
Enter fullscreen mode Exit fullscreen mode

So what's happening here?

  1. Base image:
    • Uses Node.js 22.10.0 on Alpine 3.19, providing a lightweight base image.
    • The LABEL instruction adds metadata to the image.
  2. Working directory:
    • Sets up /app as the working directory for subsequent instructions.
  3. Dependency installation:
    • Copies package.json and package-lock.json (if it exists) to the working directory.
    • Runs npm install to install dependencies.
  4. Application code:
    • Copies the rest of the application code into the container.
  5. Port exposure:
    • Exposes port 3000, which is typically used by Express.js applications.
  6. Start command:
    • Specifies the command to run the application using node index.js.

This approach is simpler than the multi-stage build we used for Astro, as Express.js applications typically don't require a separate build step.

Make sure to add the .dockerignore file to ignore the node_modules folder and npm debug logs. This will speed up the build process and reduce the image size.

Deployment

You can deploy this Docker container to any cloud provider that supports Docker. For example, you could use platforms like Heroku, DigitalOcean, or AWS ECS. Because I am the co-founder of Sliplane, I will show you how to deploy it there.

After signing up, you can create a new service by selecting your Github Repository. Then just keep the default settings and click on deploy.

Sliplane Service Create

After deployment, your Express.js app will be available under a subdomain of sliplane.app, usually it's just your service name.

You can also see the logs of your app, see metrics such as CPU and memory usage, add persistent storage, and much more. Whenever you push to your repository, Sliplane will automatically deploy your app.

If you want to try out Sliplane, the first 2 days are free! Try it out and let me know what you think :)

Deploy ExpressJS in 2 Minutes 🚀

Next Steps

Is there anything else you want to know? Do you need help dockerizing your Express.js app? Do you need help deploying it to a specific platform? Feel free to reach out!
You can find me on X or just comment here on this blog.

Cheers,

Jonas

Top comments (17)

Collapse
 
tinkermakar profile image
Makar

it's also a good practice to switch add USER node in the Dockerfile, so as your in-docker runtime was not the root user. If I am not mistaken, you also need to run RUN chown -R node /app so as that node user had write access to the app.

Collapse
 
code42cate profile image
Jonas Scholz

Yes! 100% true

Collapse
 
arindam_1729 profile image
Arindam Majumder

Great One Jonas!

Collapse
 
code42cate profile image
Jonas Scholz

Thanks:)

Collapse
 
wimadev profile image
Lukas Mauser

Good one! :-) Any thoughts on express vs h3? 👀

Collapse
 
code42cate profile image
Jonas Scholz

I don't think I've ever used h3, but the website is sleek so it must be good xD

Collapse
 
saqib_diar profile image
Saqib Diar

One basic question always bother me.

Let's say I want to deploy my NodeJs project on hostinger vps, so without using docker approach I will install NodeJs MySQL express etc and then I will pull code from my repo and install dependency and then start pm2.

But Now let's say my manager asked me to implement docker, I will create the docker image then container and then let say I deployed that container, now what?

Now that container contain my entire code?

Like I won't need pull from the GitHub to bring my whole code into my VPS?

Or I would just run docker there?

Means I won't be having code on server? Just docker file or what?

Collapse
 
inspiraller profile image
steve • Edited

I had the same question when I first was introduced to docker. What is it good for? As a front end developer doing react its not really important. As a full stack developer it opens doors.

Question:
"Now that container contain my entire code?"

Answer:
Yes and no.

Once you build your docker image, think of that like your build of a computer operating system with all its dependencies. You aren't going to build a whole windows operating system with hardware drivers, microsoft office, email etc. You are building the equivalent of a node dist folder ( but - for full stack, not just front end code ). The bare minimum of production ready dependencies.

1 Dockerfile = build image
You might build nginx and react app in one Dockerfile because nginx is going to serve the static build content of your react production code.

2 Dockerfiles = 2 build images, that will communicate with each other over docker network.

You might build nextjs server which runs on port 3000 and nginx which runs on port 80. Nginx is reverse proxy to nextjs server because they run on separate ports. Here you have two separate Dockerfiles images built but a docker compose file which works them together, or if you were deploying these to a cloud service like aws, intead of a docker compose file you have a task definition file respectively.

Answer yes:
Yes it contains your build image.

Yes it does once you built your image:
docker build myproject . -t myproject:versionX

myproject:versionX contains all your "BUILD" code per Dockerfile. That can be deployed to the docker registry.

Answer no:
That being said, all that above is your deployed code. You still need to store your development code.

Question:
"Like I won't need pull from the GitHub to bring my whole code into my VPS?"

No. You may have built your production code and stored that in docker registry or other cloud hosting space like amazon ecr, but you have not stored your development code. Ie your Dockerfile and all your development code. That all needs to be under revision control.

Question:
So why use docker at all?

Dockerfile does a few things:

  1. It is instruction file for any os (linux, windows whatever) in whole os dependencies for your application to work. Don't assume your implementation on windows will work on linux based environment and vice versa.
  2. Much like nodejs and npm can start up a script by: npm run myscript -- --someEnvVar value, docker does similar docker run myImage env someEnvVar myImg:version
  3. Much like you can deploy your optimised build nodejs dist/ folder to a website host, you can deploy your entire full stack infrastructure to a cloud host like aws. Ie that's your postgres db, nginx reverse proxy to nodejs, react app and any other service built from multiple Dockerfiles into production ready, versioned builds but all integrated.

I hope I answered the question.

Collapse
 
code42cate profile image
Jonas Scholz

nice reply! thanks for the long explanation, i hope that helps Saqib:)

Collapse
 
code42cate profile image
Jonas Scholz

Hi! Your Dockerfile will basically be the description of the steps you did without docker. You would install Nodejs (using a baseimage), copy the code, install dependencies etc the same, but Docker would do that when you build your image. Your image will then contain the final state of your files basically, which you can use to then run a container. Does that make sense?

Collapse
 
marco45palomo profile image
Marco Palamede

Nicely done Jonas, but can you deploy some docker-compose file on sliplane?

Collapse
 
code42cate profile image
Jonas Scholz

Thank you, no not yet!

Collapse
 
karthick_rajam_43e22ca31 profile image
karthick Raja M

Nice content

Collapse
 
code42cate profile image
Jonas Scholz

Thanks:)

Collapse
 
thecodingthesi profile image
Thesi

hono > express

Collapse
 
code42cate profile image
Jonas Scholz

fair

Some comments may only be visible to logged-in visitors. Sign in to view all comments.