DEV Community

Cover image for How to use containers for Node.js development
Olalekan Oladiran
Olalekan Oladiran

Posted on

How to use containers for Node.js development

Requirements

Overview

In this section, you’ll learn how to configure a development environment for your containerized application. This includes the following steps:

  • Adding a local database and persisting data
  • Configuring your container to run a development environment
  • Debugging your containerized application

Add a local database and persist data

Open your compose.yaml file in an IDE or text editor. Uncomment the database-related instructions. Below is the updated compose.yaml file:

  server:
    build:
      context: .
    environment:
      NODE_ENV: production
    ports:
      - 3000:3000
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres
    restart: always
    user: postgres
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=example
      - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
    expose:
      - 5432
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  db-data:
secrets:
  db-password:
    file: db/password.txt
Enter fullscreen mode Exit fullscreen mode

Image description

  • Open the src/persistence/postgres.js file in an IDE or text editor. You’ll notice that the application uses a PostgreSQL database and requires specific environment variables to establish a connection. Currently, these variables are not defined in the compose.yaml file.

  • Add the necessary environment variables to configure the database connection. Below is the updated compose.yaml file with the required changes:

POSTGRES_HOST: db
POSTGRES_USER: postgres
POSTGRES_PASSWORD_FILE: /run/secrets/db-password
POSTGRES_DB: example

Image description

  • Add a secrets section under the server service to ensure your application securely manages the database password. Below is the updated compose.yaml file with the necessary changes:
secrets:
      - db-password
Enter fullscreen mode Exit fullscreen mode

Image description

  • Inside the docker-nodejs-sample directory, create a new directory named db.

  • Within the db directory, create a file named password.txt. This file will store your database password securely.

  • Open the password.txt file in an IDE or text editor and enter a password of your choice. Ensure the password is on a single line with no additional lines, hidden characters, or newline characters.

  • Save all the files you’ve modified.
    Image description

  • Run the following command to start your application:

docker compose up --build

Image description

Image description

  • Add a few items to the todo list to verify data persistence.
    Image description

  • Once you’ve added items, press Ctrl+C in the terminal to stop your application.

  • Run the command docker compose rm in the terminal to remove your containers.

docker compose rm

Image description
-Refresh http://localhost:3000 in your browser and verify that the todo items persisted, even after the containers were removed and ran again.

Update your Dockerfile for Development

Open the Dockerfile in an IDE or text editor. Notice that the current Dockerfile doesn’t install development dependencies or run nodemon. You’ll need to update it to support development workflows.

Instead of creating separate Dockerfiles for production and development, you can use a multi-stage Dockerfile to handle both scenarios.

Update your Dockerfile to the following multi-stage configuration:

FROM node:${NODE_VERSION}-alpine as base
WORKDIR /usr/src/app
EXPOSE 3000

FROM base as dev
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci --include=dev
USER node
COPY . .
CMD npm run dev

FROM base as prod
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev
USER node
COPY . .
CMD node src/index.js
Enter fullscreen mode Exit fullscreen mode

Image description
In the Dockerfile, you start by adding a label (base) to the FROM node:${NODE_VERSION}-alpine statement. This allows you to reference this build stage in subsequent stages. Next, you introduce a new build stage labeled dev, which installs development dependencies and starts the container using npm run dev. Finally, you add a prod stage that excludes development dependencies and runs the application using node src/index.js.

Update your Compose file for development

  • To run the dev stage with Compose, update your compose.yaml file. Open the file in an IDE or text editor and add the target: dev instruction to target the dev stage from your multi-stage Dockerfile.

  • Additionally, add a new volume to the server service for a bind mount. For this application, mount ./src from your local machine to /usr/src/app/src in the container.

  • Finally, publish port 9229 to enable debugging.
    Image description

Run your development container and debug your application

Run the following command to run your application with the new changes to the Dockerfile and compose.yaml file.

docker compose up --build

  • Open a browser and verify that the application is running at http://localhost:3000 Image description
  • Any changes made to the application’s source files on your local machine will now be instantly reflected in the running container.

  • Open the docker-nodejs-sample/src/static/js/app.js file in an IDE or text editor and update the button text on line 109 from Add Item to Add.
    Image description

Thanks for staying till the end

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

👋 Kindness is contagious

If you found this article helpful, please give a ❤️ or share a friendly comment!

Got it