PreviewDrop for Spring Boot
Deploy previews for Spring Boot apps
Push a branch, get a live preview URL. PreviewDrop builds your fat JAR, boots the embedded server, and posts the link to the pull request in under 60 seconds — no CI scripts, no serverless Java wrappers.
TL;DR
Add a multi-stage Dockerfile, connect your repo, push. PreviewDrop builds the JAR with Maven or Gradle, runs it on the JRE, and posts a TLS-terminated preview URL to the PR. Embedded Tomcat or Netty runs exactly as in production — your
@Scheduled jobs, connection pools and a warm JVM are all intact, not folded into a Lambda handler.Dockerfile
Drop this at the root of your repo. PreviewDrop picks it up on the next push and builds it into a container behind a TLS-terminated subdomain.
DockerfileFROM eclipse-temurin:21-jdk AS build WORKDIR /app COPY .mvn/ .mvn COPY mvnw pom.xml ./ RUN ./mvnw dependency:go-offline -B COPY src ./src RUN ./mvnw clean package -DskipTests FROM eclipse-temurin:21-jre WORKDIR /app COPY --from=build /app/target/*.jar app.jar EXPOSE 8080 # PreviewDrop injects PORT; Spring binds to it via server.port CMD ["sh", "-c", "java ${JAVA_OPTS} -Dserver.port=${PORT:-8080} -jar app.jar"]
Environment variables
Set these in the Variables tab of your PreviewDrop project. They're encrypted at rest and injected into every preview container at start.
| Variable | Example value | Note |
|---|---|---|
| SPRING_PROFILES_ACTIVE | preview | Activates an application-preview.yml so previews can use a lighter config than prod. |
| JAVA_OPTS | -XX:MaxRAMPercentage=75 | Cap the heap so the JVM fits the preview container instead of grabbing the whole host. |
| SPRING_DATASOURCE_URL | jdbc:postgresql://host:5432/db | Point at a shared dev DB, or use an in-memory H2 profile for UI-only previews. |
Common gotchas
Bind to the injected PORT, not hard-coded 8080
PreviewDrop routes traffic to whatever port your app listens on via the
PORT env var. Pass -Dserver.port=${PORT} (as in the Dockerfile CMD) or set SERVER_PORT. A hard-coded port still works as long as it matches what the proxy expects, but reading PORT is the safe default.Commit the Maven wrapper with the executable bit
The build calls
./mvnw, which must be committed and executable. Windows checkouts often drop the exec bit — restore it once with git update-index --chmod=+x mvnw so the Linux build can run it. (Gradle: swap in ./gradlew bootJar.)Skip the test suite in the image build
The Dockerfile uses
-DskipTests. Preview builds should be fast — your full suite belongs in CI, not on the critical path to a preview URL. Keeping the build lean is what keeps you inside the ~60-second window.Cap the JVM heap
By default the JVM sizes its heap from total host memory, which can exceed a preview container and trigger an OOM kill. Set
JAVA_OPTS=-XX:MaxRAMPercentage=75 (or an explicit -Xmx256m) so the heap stays inside the container limit.Why not Vercel or Netlify?
Vercel and Netlify have no JVM runtime. “Serverless Java” options wrap a single handler in a Lambda, but you lose the embedded Tomcat/Netty server,
@Scheduled jobs, hosted background workers, and a warm JVM with live connection pools. PreviewDrop runs your fat JAR directly — the same container shape as production, used as a per-PR deploy preview.Preview your Spring Boot app in 5 minutes
Connect a repo, push a branch, get a URL. No credit card, no trial clock.
Start free