Spring Boot applications can be deployed as executable JARs, WAR files, or native images. The executable JAR is the most common approach.

Executable JAR

Spring Boot repackages your JAR with an embedded server:

  <build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
  

Build and run:

  mvn clean package -DskipTests
java -jar target/myapp-1.0.0.jar

# With JVM options
java -Xms512m -Xmx1g -jar target/myapp-1.0.0.jar

# With profile
java -jar target/myapp-1.0.0.jar --spring.profiles.active=prod
  

Externalized Configuration

  java -jar myapp.jar \
  --spring.datasource.url=jdbc:postgresql://db:5432/mydb \
  --server.port=8080 \
  --spring.profiles.active=prod
  

Environment variables (Spring relaxed binding):

  export SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
export SERVER_PORT=8080
java -jar myapp.jar
  

Docker Deployment

  FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY target/myapp-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
  

Multi-stage build:

  FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY . .
RUN ./mvnw package -DskipTests

FROM eclipse-temurin:21-jre-alpine
COPY --from=build /app/target/myapp-1.0.0.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
  

Kubernetes

  apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myregistry/myapp:1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: prod
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
  

WAR Deployment

For external Tomcat:

  @SpringBootApplication
public class Application extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Application.class);
    }
}
  
  <packaging>war</packaging>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>
  

GraalVM Native Image

  <plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
</plugin>
  
  mvn -Pnative native:compile
./target/myapp  # native binary, fast startup
  

Best Practices

  • Use profiles (dev, staging, prod) for environment-specific config
  • Externalize all secrets — never hardcode in JAR
  • Configure health probes for Kubernetes deployments
  • Set JVM heap limits appropriate for container memory
  • Use multi-stage Docker builds for smaller images