Docker Compose Setup
Purpose and Scope
This document describes the Docker Compose orchestration configuration for TalentSync, which defines the multi-container architecture that runs the complete application stack in production. The setup includes three primary services: PostgreSQL database (db), FastAPI backend (backend), and Next.js frontend (frontend). This page covers service definitions, networking, volume management, environment variable configuration, and inter-service dependencies.
For Docker image build details, see Docker Images & Build Process. For CI/CD deployment automation, see CI/CD Pipeline. For environment variable documentation, see Environment Configuration.
Container Architecture Overview
The Docker Compose configuration defines a three-tier containerized application stack with shared networking and persistent storage.
Diagram: Docker Compose Service Architecture

Sources: docker-compose.yaml1-78
Service Definitions
Database Service (db)
The db service runs PostgreSQL 16 with persistent storage and automatic restart policies.
| Configuration | Value | Description |
|---|---|---|
| Service Name | db |
Internal DNS hostname for database access |
| Image | postgres:16 |
Official PostgreSQL image, version 16 |
| Restart Policy | always |
Container automatically restarts on failure |
| Port | 5432 |
Internal only, not exposed externally |
| Volume | postgres_data:/var/lib/postgresql/data |
Persistent database storage |
| Network | TalentSync |
Internal bridge network |
Environment Variables:
The database service requires three environment variables loaded from .env:
POSTGRES_DB- Database namePOSTGRES_USER- Database usernamePOSTGRES_PASSWORD- Database password
These variables are passed both via env_file and explicitly in the environment section to ensure PostgreSQL image initialization works correctly.
Sources: docker-compose.yaml4-17
Backend Service (backend)
The backend service builds a custom Python image containing the FastAPI application, ML models, and NLP processing libraries.
| Configuration | Value | Description |
|---|---|---|
| Service Name | backend |
Internal DNS hostname for API access |
| Build Context | ./backend |
Backend directory with Dockerfile |
| Dockerfile | Dockerfile |
Multi-stage build configuration |
| Base Image | python:3.13-slim |
Python 3.13 slim variant |
| Restart Policy | always |
Container automatically restarts on failure |
| Port | 8000 |
Internal only, accessed via frontend |
| Volume | ./backend/uploads:/app/uploads |
Persistent file upload storage |
| Dependencies | db |
Waits for database before starting |
| Network | TalentSync |
Internal bridge network |
Environment Variables:
The backend requires database connectivity and API keys:
DATABASE_URL- Constructed aspostgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=publicGOOGLE_API_KEY- For Google Gemini 2.0 Flash LLMTAVILY_API_KEY- For web search agent- Additional variables loaded from
.env
Note the use of @db:5432 in the database URL, which references the db service name for internal DNS resolution.
Command Execution:
The backend service executes: python -m uvicorn app.main:app --host 0.0.0.0 --port 8000
Sources: docker-compose.yaml19-40 backend/Dockerfile1-33
Frontend Service (frontend)
The frontend service builds a custom Bun-based Next.js image that serves the web application and manages database migrations.
| Configuration | Value | Description |
|---|---|---|
| Service Name | frontend |
External-facing web server |
| Build Context | ./frontend |
Frontend directory with Dockerfile |
| Dockerfile | Dockerfile |
Multi-stage build with Bun runtime |
| Base Image | oven/bun:1-slim |
Bun JavaScript runtime |
| Restart Policy | always |
Container automatically restarts on failure |
| Port Mapping | 3000:3000 |
Only externally exposed service |
| Dependencies | db, backend |
Waits for both services before starting |
| Network | TalentSync |
Internal bridge network |
Environment Variables:
The frontend requires configuration for authentication, database access, and backend communication:
NODE_ENV- Set toproductionNEXTAUTH_URL- Set tohttps://talentsync.tashif.codesfor production domainDATABASE_URL- Same PostgreSQL connection string as backendBACKEND_URL- Set tohttp://backend:8000for internal service-to-service communicationNEXTAUTH_SECRET- Loaded from.envfor session encryption- OAuth credentials (Google, GitHub) - Loaded from
.env - Email server settings - Loaded from
.env
Startup Command:
The frontend executes a multi-step startup sequence:
sh -c "bunx prisma migrate deploy && bun prisma/seed.ts && bun run start"
This sequence performs:
bunx prisma migrate deploy- Apply pending database migrationsbun prisma/seed.ts- Seed initial data (if any)bun run start- Start the Next.js production server
Sources: docker-compose.yaml42-68
Network Configuration
Diagram: Internal Service Communication

The Docker Compose configuration creates a single user-defined bridge network named TalentSync that enables service discovery via DNS.
Network Properties:
| Property | Value | Behavior |
|---|---|---|
| Network Name | TalentSync |
Defined at docker-compose.yaml75-76 |
| Driver | bridge |
Standard Docker bridge networking |
| DNS Resolution | Enabled | Services can reference each other by service name |
| Isolation | Yes | Services are isolated from host network |
Service Discovery:
Each service is accessible via its service name as a hostname:
dbresolves to the database container's internal IPbackendresolves to the backend container's internal IPfrontendresolves to the frontend container's internal IP
This enables the frontend to make API calls using http://backend:8000 and both services to connect to the database using @db:5432 in connection strings.
External Access:
Only the frontend service exposes a port to the host (3000:3000). The backend and database are not directly accessible from outside the Docker network, providing security through network isolation. External traffic flows through the frontend, which proxies API requests to the backend via internal networking.
Sources: docker-compose.yaml74-76 docker-compose.yaml28 docker-compose.yaml60
Volume Management
The Docker Compose stack defines two types of persistent storage for data that must survive container restarts.
Diagram: Volume Mapping

Named Volume: postgres_data
The database uses a Docker-managed named volume for PostgreSQL data persistence.
| Property | Value |
|---|---|
| Volume Name | postgres_data |
| Driver | local |
| Container Mount | /var/lib/postgresql/data |
| Lifecycle | Persists even if containers are removed |
| Location | Managed by Docker (typically /var/lib/docker/volumes/) |
This volume ensures that database contents (tables, indexes, user data) survive container recreation, updates, and restarts. When the db service is recreated, it reattaches to the same volume, preserving all data.
Sources: docker-compose.yaml14-15 docker-compose.yaml70-72
Bind Mount: ./backend/uploads
The backend service uses a bind mount to persist uploaded resume files on the host filesystem.
| Property | Value |
|---|---|
| Host Path | ./backend/uploads (relative to docker-compose.yaml) |
| Container Mount | /app/uploads |
| Purpose | Store user-uploaded PDF, DOCX, and TXT files |
| Lifecycle | Directly accessible on host filesystem |
This bind mount allows uploaded files to be:
- Persisted across container restarts
- Backed up by standard filesystem backup tools
- Accessed directly from the host for debugging
- Shared across multiple backend container instances (if scaling horizontally)
Sources: docker-compose.yaml34
Environment Variable Management
The Docker Compose configuration uses a hybrid approach for environment variable injection, combining env_file declarations with explicit environment overrides.
Diagram: Environment Variable Flow

Environment File Loading
All three services declare env_file: - ./.env, which loads all variables from the root .env file into each container's environment. This provides baseline configuration including:
- API keys (
GOOGLE_API_KEY,TAVILY_API_KEY) - Authentication secrets (
NEXTAUTH_SECRET,JWT_SECRET) - OAuth credentials (
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,GITHUB_ID,GITHUB_SECRET) - Email server configuration (
EMAIL_SERVER_HOST,EMAIL_SERVER_PORT,EMAIL_FROM) - Database credentials (
POSTGRES_DB,POSTGRES_USER,POSTGRES_PASSWORD)
Sources: docker-compose.yaml7-8 docker-compose.yaml24-25 docker-compose.yaml53-54
Environment Overrides
The environment section in each service definition explicitly sets or overrides specific variables for Docker Compose networking:
Database Service:
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
These explicit declarations ensure the PostgreSQL image initializes correctly, as it requires these specific variable names.
Backend Service:
environment:
DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public"
The DATABASE_URL is constructed dynamically, using @db:5432 to reference the database service by its Docker Compose service name.
Frontend Service:
environment:
NODE_ENV: production
NEXTAUTH_URL: https://talentsync.tashif.codes
DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public"
BACKEND_URL: http://backend:8000
The frontend explicitly overrides networking URLs to use internal service names (http://backend:8000) and the production domain for NextAuth callbacks.
Sources: docker-compose.yaml9-13 docker-compose.yaml26-32 docker-compose.yaml55-62
Service Dependencies and Startup Order
Docker Compose orchestrates the startup sequence using depends_on directives to ensure services start in the correct order.
Diagram: Service Startup Dependency Graph

Dependency Declarations
The depends_on configuration defines service startup ordering:
Backend depends on Database:
backend:
depends_on:
- db
The backend service waits for the db service to start before launching. This ensures the database is available when the FastAPI application attempts to connect.
Frontend depends on Database and Backend:
frontend:
depends_on:
- db
- backend
The frontend service waits for both db and backend to start before executing its startup command. This is critical because the frontend runs Prisma migrations (bunx prisma migrate deploy) that require database connectivity.
Sources: docker-compose.yaml37-38 docker-compose.yaml64-66
Startup Sequence
The complete startup sequence when running docker compose up:
-
Database Initialization (3-5 seconds)
- PostgreSQL 16 container starts
- Mounts
postgres_datavolume - Initializes database with
POSTGRES_DB,POSTGRES_USER,POSTGRES_PASSWORD - Begins listening on port 5432
-
Backend Initialization (5-10 seconds)
- Python 3.13 container starts
- Loads ML models (
best_model.pkl,tfidf.pkl) - Connects to database using
DATABASE_URL - Starts Uvicorn server on port 8000
- FastAPI application begins serving requests
-
Frontend Initialization (10-15 seconds)
- Bun container starts
- Executes
bunx prisma migrate deployto update database schema - Executes
bun prisma/seed.tsto seed initial data - Executes
bun run startto launch Next.js production server - Application becomes accessible on port 3000
Important Note: depends_on only ensures start order, not readiness. If the backend takes longer than expected to initialize, the frontend may attempt migrations before the backend is fully ready. However, Prisma's connection retry logic typically handles this gracefully.
Sources: docker-compose.yaml63
Inter-Service Communication Patterns
The three services communicate using internal DNS resolution within the TalentSync network.
Frontend → Backend Communication
The frontend makes HTTP requests to the backend for all AI/ML operations:
- Connection URL:
http://backend:8000 - Environment Variable:
BACKEND_URL - Usage Pattern: Server-side API calls from Next.js API routes
Example communication flows:
- Resume analysis:
POST http://backend:8000/analyze_resume - ATS evaluation:
POST http://backend:8000/ats_evaluate - Cold mail generation:
POST http://backend:8000/generate_cold_mail
The backend hostname resolves to the backend container's internal IP address within the Docker network.
Sources: docker-compose.yaml60
Frontend → Database Communication
The frontend connects directly to PostgreSQL for user authentication and session management:
- Connection URL:
postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public - Environment Variable:
DATABASE_URL - Usage Pattern: Prisma ORM queries from NextAuth and application code
The connection string uses @db:5432 where db is the PostgreSQL service name.
Sources: docker-compose.yaml59
Backend → Database Communication
The backend also connects to PostgreSQL, primarily for storing resume analysis results:
- Connection URL: Same as frontend, using
@db:5432 - Environment Variable:
DATABASE_URL - Usage Pattern: Direct database operations (if any) and potential future features
Note that in the current architecture, the backend primarily performs stateless AI operations, with the frontend handling most database interactions through Prisma.
Sources: docker-compose.yaml28
Communication Security
All inter-service communication occurs over the internal TalentSync bridge network, which is isolated from external networks. Only the frontend's port 3000 is exposed to the host, meaning:
- The backend API (
port 8000) is not accessible from outside the Docker network - The PostgreSQL database (
port 5432) is not accessible from outside the Docker network - All API keys and secrets remain within the Docker environment
This network isolation provides defense-in-depth security, ensuring that even if the frontend is compromised, attackers cannot directly access backend services or the database.
Sources: docker-compose.yaml51-52 docker-compose.yaml16-17 docker-compose.yaml39-40
Operational Commands
Starting the Stack
docker compose up -d
Starts all three services in detached mode. The -d flag runs containers in the background. Services start in dependency order: db → backend → frontend.
Stopping the Stack
docker compose down
Stops and removes all containers. Volumes (postgres_data and ./backend/uploads) are preserved.
Rebuilding After Code Changes
docker compose build
docker compose up -d
Rebuilds container images from updated Dockerfiles and restarts services. This is necessary after code changes to the frontend or backend.
Viewing Logs
# All services
docker compose logs -f
# Specific service
docker compose logs -f frontend
docker compose logs -f backend
docker compose logs -f db
The -f flag follows log output in real-time.
Checking Service Status
docker compose ps
Shows running status, ports, and health of all services.
Sources: docker-compose.yaml1-78