Skip to main content
This guide walks you through deploying the Library Management System using Docker containers. The application uses a multi-container setup orchestrated with Docker Compose.

Prerequisites

Before you begin, ensure you have the following installed on your system:
The application uses multi-stage Docker builds to optimize image sizes and improve security.

Quick start

1

Clone the repository

Clone the project repository to your local machine:
git clone https://github.com/yigit-7/library-management-system.git
cd library-management-system
2

Configure environment variables

Create a .env file from the example template:
cp .env.example .env
Open the .env file and configure the required variables. See the environment variables page for detailed information.
3

Start the application

Launch all services using Docker Compose:
docker compose -f compose.yaml up --build
The --build flag ensures Docker builds the latest images for the frontend and backend services.
4

Verify deployment

Once all containers are running, access the application:

Container architecture

The application consists of four main services:

Database service

PostgreSQL 15 database running on Alpine Linux for data persistence.
  • Image: postgres:15-alpine
  • Container name: library-db
  • Port mapping: 5432:5432
  • Volume: postgres_data:/var/lib/postgresql/data
  • Restart policy: always

Backend service

Spring Boot application handling all business logic and API endpoints.
  • Build context: ./apps/spring-boot-app
  • Container name: library-backend
  • Port mapping: ${BACKEND_PORT:-8080}:8080 (defaults to 8080)
  • Restart policy: always
  • Dependencies: Database and cache services must be healthy

Cache service

Redis cache for improving application performance.
  • Image: redis:7-alpine
  • Container name: library-cache
  • Internal port: 6379
  • Restart policy: always

Frontend service

Next.js application providing the user interface.
  • Build context: ./apps/nextjs-app
  • Container name: library-frontend
  • Port mapping: 3000:3000
  • Restart policy: always
  • Dependencies: Backend service must be healthy

Health checks

All services include health checks to ensure proper startup sequencing and monitoring.
healthcheck:
  test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
  interval: 10s
  timeout: 5s
  retries: 5
The backend and frontend services have a start_period configuration, giving them additional time to initialize before health checks begin.

Docker build process

Backend Dockerfile

The Spring Boot application uses a multi-stage build:
1

Build stage

Uses maven:3.9.7-eclipse-temurin-21 to compile the application:
  • Downloads Maven dependencies
  • Compiles source code with Java 21
  • Packages the application as a JAR file
2

Runtime stage

Uses eclipse-temurin:21-jre-alpine for a minimal runtime:
  • Installs curl for health checks
  • Creates a non-privileged user (appuser)
  • Copies the built JAR file
  • Runs the application as a non-root user

Frontend Dockerfile

The Next.js application also uses a multi-stage build:
1

Build stage

Uses node:24-alpine to build the application:
  • Installs npm dependencies
  • Runs the Next.js build process
  • Creates an optimized standalone output
2

Production stage

Uses node:24-alpine for the runtime:
  • Copies the standalone build artifacts
  • Runs as the node user for security
  • Serves the application on port 3000

Common commands

docker compose -f compose.yaml up --build

Infrastructure-only deployment

If you want to run only the database and cache services (for local development), use the infrastructure compose file:
docker compose -f compose.infra.yaml up -d
This starts:
  • PostgreSQL database on port 5432
  • Redis cache on port 6379
The infrastructure-only setup exposes Redis on port 6379. In production, you should restrict access to Redis and not expose it publicly.

Volume management

The application uses a named volume for PostgreSQL data persistence:
volumes:
  postgres_data:
To back up the database volume:
docker run --rm \
  -v library-management-system_postgres_data:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/postgres-backup.tar.gz -C /data .
To restore from a backup:
docker run --rm \
  -v library-management-system_postgres_data:/data \
  -v $(pwd):/backup \
  alpine tar xzf /backup/postgres-backup.tar.gz -C /data

Troubleshooting

Container fails to start

Check the container logs:
docker compose -f compose.yaml logs backend

Database connection issues

Verify the database is healthy:
docker compose -f compose.yaml ps database
Check database logs:
docker compose -f compose.yaml logs database

Port conflicts

If ports 3000, 5432, or 8080 are already in use, you can modify the port mappings in compose.yaml or change the BACKEND_PORT in your .env file.

Rebuilding after code changes

After making code changes, rebuild the affected service:
# Rebuild backend
docker compose -f compose.yaml up -d --build backend

# Rebuild frontend
docker compose -f compose.yaml up -d --build frontend
The application uses Spring DevTools and Next.js hot reload in development mode. However, these features only work when running the applications directly, not in Docker containers.

Build docs developers (and LLMs) love