Docker concept and command in a friendly, beginner-friendly way. Think of this like you're setting up a virtual workspace for each part of your app.
π³ What Is Docker? (in plain terms)
Imagine you're a chef and you want to cook a recipe that needs:
- Specific tools
- Specific ingredients
- A special oven
Docker is like a sealed cooking station with everything already prepped: ingredients, tools, oven β all packed into a neat box. You just plug it in anywhere, and boom! It works exactly the same.
In dev terms:
- A container = an isolated workspace with everything your app needs
- A Dockerfile = the recipe for building that container
- Docker Compose = the cookbook that runs multiple containers together (like frontend and backend)
π·ββοΈ Step-by-Step: Understanding Docker Setup
Letβs walk through the setup of a NestJS backend and a Next.js frontend, and how Docker helps us run them together on your local machine.
πΉ Step 1: The Dockerfile
β Your Appβs Recipe
Letβs start with NestJS (backend).
Hereβs the backend/Dockerfile
again β now with beginner-friendly explanation:
# 1. Start from an official Node image (like installing Node.js on a fresh computer) FROM node:18-alpine # 2. Set the directory inside the container where code will live WORKDIR /app # 3. Copy dependency files into the container COPY package.json yarn.lock ./ # 4. Install dependencies inside the container using yarn RUN yarn install # 5. Copy all the rest of your backend code into the container COPY . . # 6. Tell Docker weβll use port 3000 for this app EXPOSE 3000 # 7. Run the app in dev mode (just like yarn start:dev on your own computer) CMD ["yarn", "start:dev"]
π So in short:
- Think of this as setting up a little dev computer just for NestJS
- When you
docker build
, it runs this step-by-step to create that environment
Do the same for the frontend/Next.js, just change the port and command:
FROM node:18-alpine WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install COPY . . EXPOSE 3001 CMD ["yarn", "dev"]
πΈ Step 2: docker-compose.yml
β The Team Manager
This file lives at the root of your project and brings both frontend and backend containers to life together.
Here's what it looks like, again with full beginner-friendly explanation:
version: "3.9" # Version of Docker Compose services: # You can think of "services" as your different apps (like backend and frontend) backend: # Name of the service build: ./backend # Tells Docker to look in backend/ and use its Dockerfile ports: - "3000:3000" # Maps local port 3000 to container's port 3000 volumes: - ./backend:/app # Syncs your local backend folder into the container (for live updates!) - /app/node_modules # Exclude node_modules to avoid conflicts command: yarn start:dev # What to run when the container starts restart: unless-stopped # Restart if it crashes frontend: build: ./frontend ports: - "3001:3001" volumes: - ./frontend:/app - /app/node_modules command: yarn dev restart: unless-stopped depends_on: - backend # Make sure backend starts first
π‘ Think of docker-compose.yml
as the orchestra conductor β it starts both backend and frontend, makes sure they talk to the right ports, and even restarts them if they crash.
π Step 3: Build & Run Everything
Just open your terminal and run:
docker-compose up --build
π Whatβs happening here?
-
--build
: Builds containers from your Dockerfiles. - Starts both backend and frontend
- Maps their ports so you can visit:
- π§
http://localhost:3000
β NestJS - π¨
http://localhost:3001
β Next.js
π Step 4: Live Code Changes (Hot Reload)
Because of this line in docker-compose.yml
:
volumes: - ./frontend:/app
It means:
Any changes you make on your local machine inside
frontend/
orbackend/
are instantly visible inside the container.
So you can code like normal, and the app will auto-reload (just like without Docker).
π§Ή Step 5: Stop Everything
To stop the containers:
docker-compose down
π‘ Think of this as unplugging the cooking stations when you're done.
π Quick Reference
Concept | Meaning (Friendly) |
---|---|
Dockerfile | A recipe for building an app container |
docker build | Build the image based on the recipe |
docker-compose | A way to start multiple containers together |
volumes | Keeps your code changes synced in real time |
ports | Makes your app accessible on localhost |
CMD | The command that runs when the container starts |
π§ Final Thoughts
Youβre not just βinstalling stuff in Dockerβ β youβre creating tiny, isolated computers for each part of your app. This is great because:
- It works exactly the same on every computer (or server)
- You avoid the βit works on my machineβ problem
- Easy to scale to production later
APPLY BASIC DOCKER TO PROJECT
Local development environment with Docker for a fullstack app using Next.js (frontend) and NestJS (backend).
π§± App Architecture
- Frontend: Next.js app runs on http://localhost:3001
- Backend: NestJS app runs on http://localhost:3000
- Package manager:
yarn
- Docker: Each app runs in its own container for isolation.
π Folder Structure
my-fullstack-app/ βββ backend/ # NestJS app β βββ src/ β βββ ... βββ frontend/ # Next.js app β βββ pages/ β βββ ... βββ docker-compose.yml
Youβll have:
-
frontend/
: your Next.js app -
backend/
: your NestJS app -
docker-compose.yml
: controls how containers work together
β Step-by-Step Setup
1. Scaffold Both Apps (using yarn
)
π§ Create backend (NestJS):
npm i -g @nestjs/cli nest new backend # Choose yarn
π¨ Create frontend (Next.js):
npx create-next-app frontend --use-yarn # Choose TypeScript if you want
2. Set Up Docker for Each App
πΈ backend/Dockerfile
# Use Node image FROM node:18-alpine # Set working directory WORKDIR /app # Copy package and install deps COPY package.json yarn.lock ./ RUN yarn install # Copy all files COPY . . # Open port 3000 EXPOSE 3000 # Start NestJS in dev mode CMD ["yarn", "start:dev"]
πΈ frontend/Dockerfile
FROM node:18-alpine WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install COPY . . EXPOSE 3001 CMD ["yarn", "dev"]
3. Create docker-compose.yml
At root (my-fullstack-app/
):
version: "3.9" services: backend: build: ./backend ports: - "3000:3000" volumes: - ./backend:/app - /app/node_modules command: yarn start:dev restart: unless-stopped frontend: build: ./frontend ports: - "3001:3001" volumes: - ./frontend:/app - /app/node_modules command: yarn dev restart: unless-stopped depends_on: - backend
π Explanation:
-
volumes
: Syncs local files β container (for live code change). -
restart: unless-stopped
: Restart if crashed. -
depends_on
: Makes sure backend starts first.
4. Update App Ports
In NestJS main.ts
:
// backend/src/main.ts await app.listen(3000);
In Next.js, default dev port is 3000. Change it in package.json
:
// frontend/package.json "scripts": { "dev": "next dev -p 3001" }
5. Add .dockerignore
(optional but recommended)
For both backend/
and frontend/
:
node_modules .dockerignore Dockerfile docker-compose.yml
6. Run the Apps
At the root of your project (my-fullstack-app/
), run:
docker-compose up --build
β After Running
- π Frontend: http://localhost:3001
- βοΈ Backend: http://localhost:3000
When you update your code (thanks to volumes), it reloads automatically π
π§ͺ Test it
- Create a simple API route in
backend/src/app.controller.ts
:
@Get('hello') getHello(): string { return 'Hello from NestJS!'; }
- Call it in
frontend/pages/index.tsx
usingfetch('http://localhost:3000/hello')
π Stop Everything
docker-compose down
π Tips
- Use
.env
for managing environment variables - Mount volume
node_modules
as anonymous to avoid conflicts - If you're on Windows, Docker Desktop is required
- If you want hot reload to work better with NestJS, install
ts-node-dev
yarn add --dev ts-node-dev # And in package.json "start:dev": "ts-node-dev --respawn --transpile-only src/main.ts"
Top comments (0)