
Docker for Beginners: How to Use Docker and Docker Compose in a NestJS Project
Docker for Beginners: How to Use Docker and Docker Compose in a NestJS Project
A complete beginner-friendly guide to Docker and Docker Compose with a real NestJS example. Learn how to containerize your application, manage environment variables, and use Docker Compose to orchestrate services like PostgreSQL.
If you've ever struggled with setting up and running your project on different machines, or if deploying your app to a server always feels like reinventing the wheel, then you're in the right place. In this blog post, we'll walk through the basics of Docker, why it's such a powerful tool for developers, and how to use it in a real-world NestJS project. We'll also explore how to handle environment variables and introduce Docker Compose to simplify your development workflow.
What is Docker?
Why Docker?
- Consistency across environments: Run the same code in development, staging, and production.
- Simplified setup: No need to install Node.js, databases, or other tools manually.
- Isolation: Keeps your app's dependencies isolated from the host machine.
- Portability: Run your app on any machine with Docker installed.
Installing Docker
To get started, install Docker from docker.com.
Once installed, verify it's working:
docker --version
Creating a NestJS App (If you don't have one already)
npm i -g @nestjs/cli nest new my-nest-app cd my-nest-app
Dockerizing a NestJS App
1. Create a .dockerignore
File
node_modules dist Dockerfile docker-compose.yml .env
Why?
The .dockerignore
file works like .gitignore
, telling Docker which files/folders to exclude when building the image. This reduces build time and keeps your final image clean from unnecessary files like local dependencies, compiled output, and sensitive configuration files.
2. Create a Dockerfile
# Stage 1: Build FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # Stage 2: Run FROM node:18-alpine WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules COPY .env . CMD [ "node", "dist/main.js" ]
What is a Dockerfile?
A Dockerfile
is a script of instructions on how to build a Docker image. Think of it as a recipe to prepare your app in a container. It tells Docker which base image to use, how to install dependencies, how to build the app, and how to run it.
Explanation of Key Commands:
FROM
: Sets the base image. We usenode:18-alpine
for a small, secure Node.js environment.WORKDIR
: Defines the working directory inside the container.COPY
: Copies files from your project into the container.RUN
: Executes shell commands, like installing dependencies or building the project.CMD
: The default command to run when the container starts (our NestJS app).
💡 This Dockerfile uses multi-stage builds to keep the final image small by separating the build and run phases.
3. Handling Environment Variables
Make sure your NestJS app uses @nestjs/config
:
npm install @nestjs/config
In main.ts
or your module:
import { ConfigModule } from '@nestjs/config'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, }), ], })
Add a .env
file:
PORT=3000
Read it in your code:
const port = process.env.PORT || 3000;
🔒 Never commit .env
to Git. It should stay private and out of version control.
Docker Compose: Simplify Multi-Container Setups
Docker Compose lets you define and run multi-container Docker applications. It's perfect for combining services like your NestJS app + a database.
Example: docker-compose.yml
version: '3.8' services: app: build: . ports: - "3000:3000" env_file: - .env depends_on: - db db: image: postgres:15 restart: always environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: myapp volumes: - pgdata:/var/lib/postgresql/data volumes: pgdata:
Why use Docker Compose?
Imagine needing to start your backend server, a PostgreSQL database, and maybe a Redis instance — all configured to talk to each other. Docker Compose lets you define all of these in a single file and start them with one command, making local development and production orchestration much simpler.
Then run:
docker-compose up --build
Your NestJS app will start on port 3000 and be connected to a PostgreSQL database container.
Useful Docker Commands
- Build image:
docker build -t my-nest-app .
- Run container:
docker run -p 3000:3000 my-nest-app
- List containers:
docker ps
- Stop containers:
docker-compose down
Visual Overview
NestJS → Compiled → Docker Container → Port 3000 exposed → Connected to DB (Postgres)
Conclusion
Docker simplifies development, improves consistency, and is essential for modern app deployment. By containerizing your NestJS application and using Docker Compose, you reduce setup time, avoid "it works on my machine" issues, and prepare your app for production scalability.
If you're just getting started with backend development or looking to modernize your workflow, learning Docker is an investment that pays off quickly.
Need help setting up Docker for your project? Feel free to reach out or connect with me on LinkedIn.