# Build a Node.js Hello World Docker container

> Learn how to build a simple Node.js Hello World Docker container from scratch, writing the Dockerfile, running docker build, and mapping ports.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2020-07-14 | Topics: [Docker](https://flaviocopes.com/tags/docker/) | Canonical: https://flaviocopes.com/docker-node-container-example/

In the [Dockerfile introduction](https://flaviocopes.com/docker-dockerfiles/) post I introduced a simple [Node.js](https://flaviocopes.com/nodejs/) Dockerfile example:

```
FROM node:14
WORKDIR /usr/src/app
COPY package*.json app.js ./
RUN npm install
EXPOSE 3000
CMD ["node", "app.js"]
```

The `node:14` tag you start from matters for image size — I built a free [Docker base image size comparison](https://flaviocopes.com/tools/base-image-sizes/) that compares common Node base images.

> NOTE: use **double quotes** in the `CMD` line. Single quotes will result in an error. 

Let's use this Dockerfile to build an [image](https://flaviocopes.com/docker-images/), and then run the [container](https://flaviocopes.com/docker-containers/).

I'm going to create this file in the `dev/docker/examplenode` folder. I create a simple Node.js app in the `app.js` file, using Express:

```js
const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello World!'))
app.listen(3000, () => console.log('Server ready'))
```

Super simple, but we have one dependency. I need to add it to the `package.json` file, so I run

```sh
npm init -y
npm install express
```

Now you can run `node app.js` and make sure it works:

![Browser showing Hello World message at localhost:3000](https://flaviocopes.com/images/docker-node-container-example/Screen_Shot_2020-07-05_at_11.30.33.png)

Stop this process and let's create a Docker Image from this.

All you need are the `app.js`, `package.json` and `package-lock.json` files.

And the Dockerfile. Create a `Dockerfile` file in the same folder, with no extension (not Dockerfile.txt).

You can freely delete the `node_modules` folder that now contains the Express library and its dependencies, but you can also create a `.dockerignore` file and add `node_modules` inside it, to make Docker ignore this folder completely.

It works like `.gitignore` in [Git](https://flaviocopes.com/git/).

Run the command 

```
docker build -t examplenode .
```

![Terminal output showing docker build command downloading Node.js base image and installing dependencies](https://flaviocopes.com/images/docker-node-container-example/Screen_Shot_2020-07-05_at_11.35.26.png)

It will take a while to download the Node image and run `npm install`, then you'll get a successful message.

It's important to note that after you first download a base image like the `node` one we use here, that will be cached locally, so you don't need to download it again and the image building process will be much faster.

Now we can run a container from the image:

```
docker run -d -p 3000:3000 --name node-app examplenode
```

![Terminal showing complete docker build process and successful docker run command with container ID](https://flaviocopes.com/images/docker-node-container-example/Screen_Shot_2020-07-05_at_12.24.00.png)

Now you can see the image running in [Docker Desktop](https://flaviocopes.com/docker-desktop-manage-container/):

![Docker Desktop interface showing running node-app container with examplenode image on port 3000](https://flaviocopes.com/images/docker-node-container-example/Screen_Shot_2020-07-05_at_12.24.36.png)

And you can click the "Open in browser" button to open the app running on port 3000:

![Browser showing Hello World message at localhost:3000 running inside Docker container](https://flaviocopes.com/images/docker-node-container-example/Screen_Shot_2020-07-05_at_12.25.16.png)

Just like before! Except now the app is running in its own container, completely isolated, and we can run whatever version of Node we want in the container, with all the benefits Docker gives us.

For example you can remove the container and run it on port 80 instead of 3000, with:

```
docker run -d -p 80:3000 --name node-app examplenode
```

The image does not need to change, all you change is the port mapping. Here's the result:

![Browser showing Hello World message at localhost port 80 after remapping container port](https://flaviocopes.com/images/docker-node-container-example/Screen_Shot_2020-07-05_at_12.26.31.png)
