Docker Compose for Full Stack Application: Setup and Example
Use
docker-compose.yml to define all parts of your full stack app like frontend, backend, and database as services. Run docker-compose up to start them together with one command.Syntax
A docker-compose.yml file defines multiple services for your app. Each service has a name and specifies the Docker image, ports, volumes, and environment variables it needs.
Key parts:
- version: Compose file format version.
- services: List of app parts like frontend, backend, database.
- image/build: Docker image or build context for each service.
- ports: Map container ports to host ports.
- volumes: Share files between host and container.
- environment: Set environment variables inside containers.
yaml
version: '3.8' services: frontend: build: ./frontend ports: - "3000:3000" backend: build: ./backend ports: - "5000:5000" environment: - DATABASE_URL=postgres://user:pass@db:5432/mydb db: image: postgres:15 environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - POSTGRES_DB=mydb volumes: - db-data:/var/lib/postgresql/data volumes: db-data: {}
Example
This example shows a full stack app with three services: a React frontend, a Node.js backend, and a PostgreSQL database. The frontend runs on port 3000, backend on 5000, and the database stores data persistently.
yaml
version: '3.8' services: frontend: build: ./frontend ports: - "3000:3000" depends_on: - backend backend: build: ./backend ports: - "5000:5000" environment: - DATABASE_URL=postgres://user:pass@db:5432/mydb depends_on: - db db: image: postgres:15 environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - POSTGRES_DB=mydb volumes: - db-data:/var/lib/postgresql/data volumes: db-data: {}
Output
Creating network "project_default" with the default driver
Creating volume "project_db-data" with default driver
Creating project_db_1 ... done
Creating project_backend_1 ... done
Creating project_frontend_1 ... done
Common Pitfalls
Common mistakes include:
- Not specifying
depends_onto control startup order, causing services to fail if dependencies are not ready. - Forgetting to map ports, so services are not accessible from outside.
- Missing environment variables needed for database connections.
- Not using volumes for databases, losing data on container restart.
yaml
version: '3.8' services: backend: build: ./backend ports: - "5000:5000" environment: - DATABASE_URL=postgres://user:pass@db:5432/mydb db: image: postgres:15 environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - POSTGRES_DB=mydb # Missing depends_on and volumes --- Corrected version --- version: '3.8' services: backend: build: ./backend ports: - "5000:5000" environment: - DATABASE_URL=postgres://user:pass@db:5432/mydb depends_on: - db db: image: postgres:15 environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - POSTGRES_DB=mydb volumes: - db-data:/var/lib/postgresql/data volumes: db-data: {}
Quick Reference
Tips for Docker Compose full stack apps:
- Use
depends_onto ensure services start in the right order. - Map ports to access services from your machine.
- Use volumes for databases to keep data safe.
- Set environment variables for configuration like database URLs.
- Run
docker-compose up --buildto rebuild images if code changes.
Key Takeaways
Define all parts of your full stack app as services in a single docker-compose.yml file.
Use depends_on to control service startup order and avoid connection errors.
Map ports and use volumes to make services accessible and data persistent.
Set environment variables for service configuration like database connections.
Run docker-compose up --build to start and rebuild your full stack app easily.