Docker Compose Complete Guide: From Beginner to Interview Ready

Hi there! I'm Aditya, a passionate Full-Stack Developer driven by a love for turning concepts into captivating digital experiences. With a blend of creativity and technical expertise, I specialize in crafting user-friendly websites and applications that leave a lasting impression. Let's connect and bring your digital vision to life!
What is Docker Compose?
Docker Compose is a tool used to define and manage multiple Docker containers using a single YAML file.
Instead of running multiple docker commands manually, Docker Compose allows you to define all services in one configuration file.
Without Compose:
docker run postgres
docker run redis
docker run backend
docker run frontend
With Compose:
docker compose up
Everything starts automatically.
Why Do We Need Docker Compose?
Modern applications rarely consist of a single container.
A typical application may contain:
| Service | Purpose |
|---|---|
| Frontend | React / Next.js |
| Backend | Node.js / Express |
| Database | PostgreSQL |
| Cache | Redis |
| Reverse Proxy | Nginx |
Managing these individually becomes difficult.
Docker Compose solves this problem.
Docker Compose Workflow
compose.yml
↓
docker compose up
↓
Network Creation
↓
Volume Creation
↓
Container Creation
↓
Application Running
Compose automatically creates:
Containers
Networks
Volumes
Service communication
Basic Docker Compose File
services:
app:
build: .
db:
image: postgres:16
This starts:
One application container
One PostgreSQL container
Services
Services are the most important concept in Docker Compose.
Each service represents a container.
services:
frontend:
build: ./frontend
backend:
build: ./backend
postgres:
image: postgres:16
Three services create three containers.
Build
Used when Docker should build an image using a Dockerfile.
services:
backend:
build: .
Equivalent command:
docker build .
Custom path:
services:
backend:
build:
context: .
dockerfile: Dockerfile.prod
Image
Used when Docker should pull an image from Docker Hub.
services:
postgres:
image: postgres:16
Examples:
image: redis:7
image: nginx:latest
image: mongo:7
Build vs Image
| Feature | Build | Image |
|---|---|---|
| Uses Dockerfile | Yes | No |
| Builds Locally | Yes | No |
| Pulls From Registry | No | Yes |
| Used For Custom Apps | Yes | Yes |
Interview Question:
When should you use build instead of image?
Answer
Use build when creating your own application image. Use image when using pre-built images from Docker Hub.
Container Name
Provides a custom container name.
services:
backend:
container_name: backend-app
Without this:
project_backend_1
With this:
backend-app
Ports
Maps host ports to container ports.
ports:
- "3000:3000"
Format:
HOST:CONTAINER
Example:
ports:
- "8080:3000"
Request:
localhost:8080
Container receives:
3000
Interview Question:
What is the format of port mapping?
Answer
HOST_PORT
Environment Variables
Pass runtime variables.
environment:
NODE_ENV: production
PORT: 3000
Example:
services:
backend:
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
Access:
process.env.DATABASE_URL
Env File
Store variables in a separate file.
.env
DATABASE_URL=mydb
PORT=3000
Compose:
env_file:
- .env
Benefits:
Cleaner configuration
Easier secret management
Volumes
Volumes persist data.
volumes:
- postgres-data:/var/lib/postgresql/data
Without volumes:
Container Deleted
↓
Data Deleted
With volumes:
Container Deleted
↓
Data Preserved
Common use cases:
PostgreSQL
MySQL
MongoDB
File uploads
Named Volumes
services:
postgres:
image: postgres:16
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Docker manages storage automatically.
Bind Mounts
Map local folders into containers.
volumes:
- .:/app
Benefits:
Live code updates
Faster development
Common for Next.js and Node.js projects.
Networks
Compose automatically creates a network.
Example:
services:
backend:
postgres:
Backend can connect to database using:
postgres
instead of:
localhost
Connection string:
DATABASE_URL=postgresql://user:pass@postgres:5432/db
Interview Question:
How do containers communicate inside Docker Compose?
Answer
Containers communicate through the automatically created Docker network using service names.
Depends On
Controls startup order.
services:
backend:
depends_on:
- postgres
Docker starts:
Postgres
↓
Backend
Important:
depends_on does not wait until the database is ready.
It only starts containers in order.
Interview Question:
Does depends_on guarantee database readiness?
Answer
No. It only guarantees startup order.
Restart Policies
Automatically restart containers.
restart: always
Options:
restart: always
restart: unless-stopped
restart: on-failure
restart: no
Common production setting:
restart: unless-stopped
Command
Override Dockerfile CMD.
Dockerfile:
CMD ["npm", "start"]
Compose:
command: npm run dev
Compose command takes precedence.
Healthcheck
Monitors container health.
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
Benefits:
Better monitoring
Automatic recovery
Production readiness
Profiles
Run only selected services.
services:
postgres:
profiles:
- development
Run:
docker compose --profile development up
Useful for:
Development
Testing
Production
Real World Example
Node.js + PostgreSQL
services:
backend:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://admin:secret@postgres:5432/app
depends_on:
- postgres
postgres:
image: postgres:16
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Start:
docker compose up
Everything starts automatically.
Common Docker Compose Commands
Start:
docker compose up
Background mode:
docker compose up -d
Stop:
docker compose down
View logs:
docker compose logs
Follow logs:
docker compose logs -f
List containers:
docker compose ps
Restart:
docker compose restart
Build:
docker compose build
Rebuild:
docker compose up --build
Common Interview Questions
What is Docker Compose?
A tool used to define and manage multi-container Docker applications using a YAML file.
Dockerfile vs Docker Compose?
| Dockerfile | Docker Compose |
|---|---|
| Builds Images | Runs Containers |
| Defines Environment | Defines Services |
| Creates Images | Creates Application Stack |
How do containers communicate?
Through Docker networks using service names.
What is depends_on?
Defines container startup order.
Does depends_on wait for readiness?
No.
What is the purpose of volumes?
Persistent data storage.
What is the difference between bind mounts and named volumes?
| Bind Mount | Named Volume |
|---|---|
| Uses Host Directory | Managed By Docker |
| Good For Development | Good For Production |
What happens when docker compose down is executed?
Containers and networks are removed.
Volumes remain unless explicitly deleted.
Can Compose build images?
Yes.
Using:
build: .
Production Best Practices
- Use explicit image versions.
image: postgres:16
Avoid:
image: postgres:latest
Use healthchecks.
Use named volumes for databases.
Store secrets in environment files.
Separate development and production configurations.
Use restart policies.
Avoid hardcoded credentials.
Keep services isolated.
Common Mistakes
| Mistake | Problem |
|---|---|
| Using latest tag | Unexpected updates |
| No volumes | Data loss |
| No healthchecks | Difficult monitoring |
| Hardcoded secrets | Security risk |
| Using localhost for DB | Container communication failure |
Docker Compose Revision Sheet
| Keyword | Purpose |
|---|---|
| services | Define containers |
| build | Build image |
| image | Pull image |
| container_name | Custom name |
| ports | Port mapping |
| environment | Runtime variables |
| env_file | External variables |
| volumes | Persistent storage |
| networks | Service communication |
| depends_on | Startup order |
| restart | Auto restart |
| command | Override CMD |
| healthcheck | Health monitoring |
| profiles | Environment-specific services |
Docker Compose Interview Scenarios
In real interviews, Docker Compose questions are usually scenario-based.
Interviewers want to evaluate:
Service communication
Networking knowledge
Volume management
Environment variables
Startup dependencies
Production readiness
This guide contains common interview scenarios and their solutions.
Scenario 1: Backend + PostgreSQL
Interview Question
You have a Node.js backend and PostgreSQL database.
Requirements:
Backend should run on port 3000
PostgreSQL should run on port 5432
Backend should connect to PostgreSQL
Database data should persist after container restart
Write a Docker Compose file.
Solution
services:
backend:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://admin:secret@postgres:5432/app
depends_on:
- postgres
postgres:
image: postgres:16
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Interview Explanation
Backend connects using:
postgres
NOT
localhost
Because containers communicate through service names.
Correct:
DATABASE_URL=postgresql://admin:secret@postgres:5432/app
Wrong:
DATABASE_URL=postgresql://admin:secret@localhost:5432/app
Follow-Up Questions
Why use a volume?
To prevent database data loss.
Why use depends_on?
To ensure PostgreSQL starts before Backend.
Does depends_on wait for database readiness?
No.
Scenario 2: Backend + Redis
Interview Question
Create a Compose file where:
Backend runs on port 3000
Redis runs on port 6379
Backend uses Redis for caching
Solution
services:
backend:
build: .
ports:
- "3000:3000"
environment:
REDIS_URL: redis://redis:6379
depends_on:
- redis
redis:
image: redis:7
Interview Explanation
Backend can access Redis using:
redis
because Redis service name becomes DNS hostname.
Follow-Up Question
How does Backend discover Redis?
Answer:
Docker Compose automatically creates a network and service names become hostnames.
Scenario 3: Frontend + Backend
Interview Question
You have:
React Frontend
Express Backend
Both should communicate through Docker network.
Frontend runs on:
localhost:5173
Backend runs on:
localhost:3000
Solution
services:
frontend:
build: ./frontend
ports:
- "5173:5173"
backend:
build: ./backend
ports:
- "3000:3000"
Communication
Frontend should call:
http://backend:3000
inside Docker network.
Not:
http://localhost:3000
Interview Trap
Many candidates use:
localhost
This is wrong because each container has its own localhost.
Scenario 4: Full Stack Application
Interview Question
Create a Compose file containing:
Next.js
Express
PostgreSQL
Redis
All services should communicate.
Solution
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
backend:
build: ./backend
ports:
- "4000:4000"
environment:
DATABASE_URL: postgresql://admin:secret@postgres:5432/app
REDIS_URL: redis://redis:6379
depends_on:
- postgres
- redis
postgres:
image: postgres:16
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- postgres-data:/var/lib/postgresql/data
redis:
image: redis:7
volumes:
postgres-data:
Architecture
Frontend
↓
Backend
↓ ↓
Redis PostgreSQL
Follow-Up Questions
How many networks are created?
Answer:
One default network.
How does Backend connect to PostgreSQL?
Answer:
Using hostname:
postgres
How does Backend connect to Redis?
Answer:
Using hostname:
redis
Scenario 5: Custom Network
Interview Question
Create two services that communicate using a custom Docker network.
Solution
services:
backend:
build: .
networks:
- app-network
postgres:
image: postgres:16
networks:
- app-network
networks:
app-network:
Architecture
backend
↓
app-network
↑
postgres
Interview Explanation
Both services belong to the same network.
Therefore:
backend
can communicate with:
postgres
Scenario 6: Multiple Networks
Interview Question
You have:
Frontend
Backend
Database
Database should NOT be accessible by Frontend.
Design the network architecture.
Solution
services:
frontend:
build: ./frontend
networks:
- public
backend:
build: ./backend
networks:
- public
- private
postgres:
image: postgres:16
networks:
- private
networks:
public:
private:
Architecture
Frontend
|
Public
|
Backend
|
Private
|
Postgres
Why?
Frontend cannot directly access PostgreSQL.
Only Backend can.
This is a common production setup.
Scenario 7: Persistent Database
Interview Question
Your PostgreSQL data disappears after container recreation.
How would you fix it?
Solution
services:
postgres:
image: postgres:16
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Follow-Up Question
What happens if the container is deleted?
Answer:
Data remains inside the volume.
Scenario 8: Environment Variables
Interview Question
Move all sensitive values out of compose.yml.
Solution
.env
POSTGRES_USER=admin
POSTGRES_PASSWORD=secret
POSTGRES_DB=app
compose.yml
services:
postgres:
image: postgres:16
env_file:
- .env
Why?
Better security.
Cleaner configuration.
Scenario 9: Health Checks
Interview Question
Ensure Backend starts only when PostgreSQL becomes healthy.
Solution
services:
postgres:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
Interview Explanation
Health checks allow Docker to monitor service readiness.
Scenario 10: Production Ready Compose
Interview Question
What would you add before deploying to production?
Expected Answer
Named volumes
Health checks
Restart policies
Environment files
Fixed image versions
Separate networks
Resource limits
Logging configuration
Example:
restart: unless-stopped
healthcheck:
volumes:
env_file:
Most Common Interview Traps
Trap 1
Using localhost between containers.
Wrong:
localhost
Correct:
service-name
Trap 2
No volume for database.
Result:
Container Deleted
↓
Data Lost
Trap 3
Using latest image tag.
Wrong:
image: postgres:latest
Correct:
image: postgres:16
Trap 4
Thinking depends_on waits for readiness.
It does not.
It only controls startup order.
Trap 5
Exposing database publicly.
Wrong:
ports:
- "5432:5432"
Not always necessary.
Expose only when needed.
15-Minute Interview Revision
| Question | Expected Answer |
|---|---|
| How do containers communicate? | Service Name |
| What creates networking? | Docker Compose |
| How to persist data? | Volumes |
| Build vs Image? | Custom vs Existing Image |
| What is depends_on? | Startup Order |
| Does depends_on wait? | No |
| How to store secrets? | env_file |
| Why healthchecks? | Readiness Monitoring |
| Why custom networks? | Isolation |
| Why named volumes? | Data Persistence |
Conclusion
Docker Compose is used to manage multiple containers as a single application. It simplifies networking, storage, environment configuration, startup order, and deployment. Understanding services, build, image, ports, environment variables, volumes, networks, and depends_on is sufficient for handling most real-world projects and Docker-related interviews.