Deploy Spring Boot Applications
Deployment options
| Option | Best for | What you provide |
|---|---|---|
| Executable JAR | VM, bare server, or simple hosting | Java runtime and configuration |
| Docker | Consistent local, CI, and production environments | Image and environment variables |
| Docker Compose | Local development with application dependencies | Compose file and volumes |
| Kubernetes | Multiple replicas and rolling deployments | Container image and manifests |
Build and run an executable JAR
Spring Boot packages the application, embedded server, and required libraries into one executable JAR. The target machine needs a compatible Java runtime, but it does not need a separately installed Tomcat.
./mvnw clean test
./mvnw clean package
java -jar target/employee-service-1.0.0.jar
# Override settings for one run
java -jar target/employee-service-1.0.0.jar \
--server.port=9090 \
--spring.profiles.active=prod
Configure each environment
Keep the same artifact across development, testing, and production. Change environment-specific values with profiles, environment variables, or a secret manager instead of rebuilding the JAR.
# application-prod.properties
server.port=8080
spring.datasource.url=DATABASE_URL
spring.datasource.username=DATABASE_USERNAME
spring.datasource.password=DATABASE_PASSWORD
spring.jpa.hibernate.ddl-auto=validate
management.endpoints.web.exposure.include=health,info,prometheus
# Runtime environment variables
SPRING_PROFILES_ACTIVE=prod
DATABASE_URL=jdbc:postgresql://db:5432/employee_portal
- Never commit database passwords, API keys, or JWT secrets.
-
Use
ddl-auto=validatewith Flyway or Liquibase in production. - Use a separate database and credentials for every environment.
Dockerize the application
Docker puts the Java runtime and application into an image. The same image can run on a developer laptop, in CI, or in a cloud platform.
Dockerfile
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/employee-service-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Build and run the image
./mvnw clean package
docker build -t javacodeex/employee-service:1.0.0 .
docker run --name employee-service \
-p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=prod \
-e DATABASE_URL=jdbc:postgresql://host.docker.internal:5432/employee_portal \
-e DATABASE_USERNAME=postgres \
-e DATABASE_PASSWORD=change-me \
javacodeex/employee-service:1.0.0
-p 8080:8080 maps the host port to the container port.
Environment variables are injected at runtime, so the image does not
contain a database password.
Multi-stage Docker build
A multi-stage build compiles the application in one stage and copies only the final JAR into a smaller runtime image.
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /workspace
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /workspace/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Run Spring Boot and PostgreSQL with Docker Compose
Compose is useful for local development because it starts the application and database together on one private network.
services:
db:
image: postgres:16
environment:
POSTGRES_DB: employee_portal
POSTGRES_USER: postgres
POSTGRES_PASSWORD: local-password
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
app:
build: .
depends_on:
- db
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: docker
DATABASE_URL: jdbc:postgresql://db:5432/employee_portal
DATABASE_USERNAME: postgres
DATABASE_PASSWORD: local-password
volumes:
postgres-data:
docker compose up --build
docker compose logs -f app
docker compose down
Inside Compose, the application connects to host db, not
localhost. A Compose service name becomes a network
hostname.
Health checks and readiness
Add Actuator so a platform can decide whether the application is alive and ready. Liveness controls restarts; readiness controls traffic.
management.endpoint.health.probes.enabled=true
management.endpoints.web.exposure.include=health,info
GET /actuator/health/liveness
GET /actuator/health/readiness
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s \
CMD wget --no-verbose --tries=1 \
--spider http://localhost:8080/actuator/health/readiness || exit 1
Deploy the container to Kubernetes
Kubernetes can run multiple copies, send traffic through a Service, and use probes to control traffic and restarts.
apiVersion: apps/v1
kind: Deployment
metadata:
name: employee-service
spec:
replicas: 2
selector:
matchLabels:
app: employee-service
template:
metadata:
labels:
app: employee-service
spec:
containers:
- name: employee-service
image: javacodeex/employee-service:1.0.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
---
apiVersion: v1
kind: Service
metadata:
name: employee-service
spec:
selector:
app: employee-service
ports:
- port: 80
targetPort: 8080
kubectl apply -f employee-service.yaml
kubectl get pods
kubectl logs -f deployment/employee-service
kubectl rollout status deployment/employee-service
Logging and monitoring
Containers should write logs to standard output so Docker, Kubernetes, or a cloud logging platform can collect them. Monitor latency, error rate, traffic, CPU, memory, and database connection usage.
logging.level.root=INFO
logging.level.com.javacodeex=INFO
logging.pattern.console=%d{ISO8601} %-5level [%X{requestId}] %logger - %msg%n
GET /actuator/health/readiness
GET /actuator/metrics/http.server.requests
GET /actuator/prometheus
CI/CD deployment flow
- Push code to the source repository.
- Run unit tests, integration tests, and security checks.
- Build the JAR and Docker image.
- Tag the image with a release or commit ID.
- Push the image to a private container registry.
- Deploy the image and wait for readiness checks.
- Stop or roll back automatically when health checks fail.
javacodeex/employee-service:1.0.0
javacodeex/employee-service:git-a1b2c3d
Deployment security
- Use HTTPS at the load balancer or ingress.
- Store secrets in a secret manager or Kubernetes Secret.
- Run containers as a non-root user where possible.
- Use a small JRE image and scan images for vulnerabilities.
- Expose only required Actuator endpoints.
- Restrict database access to the application network.
- Keep dependencies and base images patched.
Rollback and troubleshooting
Keep the previous image available and make database migrations backward compatible when possible. A deployment is incomplete until recovery has been tested.
kubectl rollout history deployment/employee-service
kubectl rollout undo deployment/employee-service
kubectl describe pod <pod-name>
kubectl logs <pod-name>
| Symptom | First checks |
|---|---|
| Container exits | Application logs, Java version, required environment variables |
| Readiness fails | Database URL, credentials, migrations, dependency health |
| 502 or 503 response | Service port, target port, readiness probe, network rules |
| Application is slow | HTTP latency, CPU, memory, and database metrics |
Production checklist
- Run tests before packaging and scan dependencies and images.
- Use an immutable, versioned JAR or Docker image.
- Keep environment configuration and secrets outside the image.
- Use database migrations and take backups before risky changes.
- Configure readiness and liveness probes.
- Set memory and CPU requests and limits for containers.
- Collect structured logs, metrics, and alerts.
- Document rollback steps and test them.
- Use HTTPS, least privilege, and restricted Actuator endpoints.
Spring Boot Deployment FAQs
Should configuration be packaged inside the JAR?
Package safe defaults only. Keep environment-specific URLs, credentials, feature flags, and secrets outside the artifact.
Should Spring Boot applications run in Docker?
Docker is useful when you need repeatable environments and consistent promotion from development to production. Use a small runtime image and scan it regularly.
What should a CI/CD pipeline verify?
Build and unit tests, integration tests, dependency and image scans, configuration checks, health verification, deployment status, and rollback readiness.
Back to Spring Boot CourseContinue learning
