DEV Community

Cover image for Learn Docker: Stop asking your stakeholders to install Node.js
Francisco Luna
Francisco Luna

Posted on

Learn Docker: Stop asking your stakeholders to install Node.js

I once asked a major stakeholder to install Postgres on his laptop just to see my progress.

It was September 2024. I was earlier in my career, and the shame of that moment still fuels my obsession with Docker and DX today.

The project was in its early stages. When the stakeholder asked to try it himself, I gave him a to-do list:

  • Install Node.js and PNPM.

  • Set up a local Postgres instance.

  • Switch to a Linux environment.

  • Manually configure credentials and run migrations.

I didn't share a project, I shared a liability. Today, I don't ship code; I ship environments.

That experience was my wake-up call. I realized that as a developer, my job isn't just to write code, but delivering value. If a stakeholder or a new teammate can't run the project in minutes, I've failed.

I'll help you save time and be more effective with one of my favorite development tools ever created: Docker.


Why using Docker? Is not that a DevOps thing?

Yes. Docker is used for DevOps. But almost no one tells you it's used for professional development environments. Would you prefer to install Docker Desktop and run a few commands to start building or:

  • Manually set up Postgres in your machine
  • Set up WSL
  • Ensure each service is running
  • Set up each service individually
  • Ensure the versions match
  • Etc

This process took my company's onboarding time from 5 days to a couple of hours.


About Docker

Docker lets you package your app with everything it needs to run; from code to runtime, and libraries into a single unit called Container; which can run in any OS and machine.

It's like a bassline. You don't notice it's important until it's gone.


Docker vs Virtual Machines (VMs)

VMs are heavy, they require a full copy of the operating system and consume significant RAM and CPU.

On the other hand, Containers share your machine's OS kernel and they only install the libraries and dependencies they need.


The Three Pieces of Docker

  1. Dockerfile: This is your blueprint. It allows you to specify Docker how you want to build the environment (OS, the Node.js version, and your dependencies)

  2. Image: The snapshot. It's what you get when you build the blueprint given by the dockerfile. It's a read-only template that contains your application and its environment.

  3. Container: This is the image in action. You can start, stop and delete environments without affecting your actual computer.


Solving the "Postgres Headache" with Docker Compose

Remember the list I gave that stakeholder? "Install Postgres, run migrations, set credentials..."

With Docker Compose, we turn that entire manual process into a single command: docker compose up.

Think of each service (application, database, message queue) as an instrument. You're combining them to create a band, but in YAML.

Docker Compose Diagram

It's important to mention this tool is used for development environments and small MVPs in production. You'll need load balancers and eventually K8s for scaling a complex system.

Time to Build

Suppose we want to dockerize a Next.js app and run a database with it, we're going to create 3 files in the root folder of the project.

  • docker-compose.yaml
  • .dockerignore
  • dockerfile

Dockerfile

This is how Docker will build the image to run our Next.js application.


FROM node:20-alpine

RUN npm install -g pnpm

WORKDIR /app

COPY package.json pnpm-lock.yaml* ./

RUN pnpm install

COPY . .

EXPOSE 3000

CMD ["pnpm", "dev"]
Enter fullscreen mode Exit fullscreen mode

Dockerignore

Just as we have our .gitignore we also have .dockerignore. This file is responsible for preventing packaging sensitive or unnecessary content from the Next.js app into the container.

node_modules
.pnpm-debug.log

.next
out
build

.env
.env.local
.env*.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

.git
.gitignore

.DS_Store
Thumbs.db
Enter fullscreen mode Exit fullscreen mode

Docker Compose File

This file is responsible for orchestrating the containers. You declare each component of your application as a service. Remember to create a Dockerfile for the core Next.js app. The data of postgres will persist on the volume we have created.

services:
  db:
    image: postgres:15-alpine
    container_name: nextjs-db
    restart: always
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: supersecretpassword
      POSTGRES_DB: db
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  app:
    build: .
    container_name: nextjs-app
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://admin:supersecretpassword@db:5432/db
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      - db
    command: pnpm dev

volumes:
  postgres_data:
Enter fullscreen mode Exit fullscreen mode

Notice I use node:20-alpine. It uses Alpine Linux under the hood; you can choose other Node.js images depending on your needs. Remember that in production environments, we optimize for image size and security surface. We also use depends_on because your app shouldn't start if the database isn't alive.

We're saving the database data in a named volume called postgres_data. This way, when we turn off the container, the data will still persist.

Tip: For resilience, combine depends_on with a healthcheck to ensure the DB is actually ready to receive traffic, not just "running".


One Command to Rule them All

With these three files in your root directory, you’ve turned a 1-hour headache setup into a 10-second command:

docker compose up
Enter fullscreen mode Exit fullscreen mode

By running this, Docker will build your Next.js app, pull the database image, set up the network between them, and start your dev server with hot-reload enabled.

You can even add startup and seeding scripts if needed.


Stop Selling Hours, Start Delivering Systems

I used to think Docker was only a complex DevOps tool until that afternoon in 2024. Where I learned that seniority isn't just about writing fancy code, but about using code as a tool for the business.

I stopped being just a programmer and became a Software Engineer. I reclaimed my time, improved my team's DX, and made sure that no stakeholder ever has to install a database on their laptop again.

If you want to scale your project or your career, start containerizing today. Your future self and your team will thank you.

What was your worst setup story? Share below in the comments!


Building a complex application or a high-performance system?

I help startups engineer scalable applications and internal tools that stay fast as they grow. See how I build scalable systems here: 👉 www.itsfranciscoluna.com

Top comments (0)