Docs menu
Java on Primcloud
How Primcloud detects a Java app, installs OpenJDK, runs Maven or Gradle, caches dependencies, and launches your process.
On this page
Primcloud detects a Java app from files in your repo, installs an OpenJDK release, runs Maven or Gradle to compile and package your code, caches dependencies between builds, and launches whatever your Procfile says to launch. There's no Dockerfile to write and no framework adapter to install.
Detection#
Primcloud runs the Java toolchain when the root of your repo holds either:
- A Maven POM:
pom.xml, or one of the polyglot POM formats (pom.atom,pom.clj,pom.groovy,pom.rb,pom.scala,pom.yaml,pom.yml). - A Gradle build file:
build.gradle,settings.gradle,build.gradle.kts, orsettings.gradle.kts.
If both a Maven POM and Gradle files are present, Maven wins. If neither is present, the build fails before it starts with a "no Java application found" error.
Install phase#
OpenJDK installs into a cached layer. The version comes from system.properties in your repo, or defaults to the latest LTS when you don't pin one; see Runtime versions for the pinning rules. OpenJDK ships as Azul Zulu builds, which are TCK-certified.
JAVA_HOME is set to the installed JDK and java is on the path, so both your build and your running process use the same toolchain.
Compile phase#
Whichever build tool detected the app runs next.
Maven. The default build is mvn clean install -DskipTests against your POM. If your repo contains a Maven wrapper (mvnw plus .mvn/wrapper/maven-wrapper.properties), Primcloud uses it, so the Maven version matches what you build with locally. Otherwise it provides a Maven for you.
Two knobs shape the command:
MAVEN_CUSTOM_GOALS: replace the defaultclean installgoals.MAVEN_CUSTOM_OPTS: replace the default-DskipTestsoptions.
Set either in the Secrets panel. See Customizing the build for the full list. A settings.xml at the repo root is picked up automatically; see Package managers.
Gradle. The default build is ./gradlew stage, run through the Gradle wrapper. The wrapper is required for Gradle apps; there's no fallback Gradle install, so commit gradlew and the gradle/wrapper/ directory. stage is a convention for producing a runnable artifact. You define what it does in build.gradle. Override the task with the GRADLE_TASK environment variable.
To raise the heap for the build itself (a large multi-module Maven build, say), set MAVEN_JAVA_OPTS; the default is -Xmx1024m.
Cache behavior#
Cached layers persist in a per-app cache between builds:
- OpenJDK: the resolved JDK, reused across builds until the pinned version changes.
- Maven local repository: the
.m2directory of resolved dependencies, somvn installdoesn't re-download everything each deploy. - Gradle caches: the Gradle build cache and dependency cache, kept for the same reason.
Launching your process#
A Procfile at the repo root defines your process types. Primcloud reads it the same way it does for every other language: one process type per line. See Pod Formations for the file format.
For a Spring Boot or WildFly Swarm app, the build generates a default web process when your repo has no Procfile, so those apps deploy without one. Every other kind of Java app declares its process in a Procfile.
A typical Spring Boot Procfile:
web: java -Dserver.port=$PORT $JAVA_OPTS -jar target/myapp-0.0.1-SNAPSHOT.jar
Micronaut and Quarkus are the same shape: build a runnable JAR and launch it:
web: java -Dmicronaut.server.port=$PORT -jar target/myapp-0.1.jar
web: java -Dquarkus.http.port=$PORT -jar target/quarkus-app/quarkus-run.jar
Port binding. Primcloud sets PORT to 5000 on the web process, and your launch command has to bind to it, by passing -Dserver.port=$PORT (Spring Boot), -Dmicronaut.server.port=$PORT (Micronaut), -Dquarkus.http.port=$PORT (Quarkus), or by reading the env var directly in your startup code. Non-web process types (a worker, say) don't get a PORT and shouldn't bind one.
Runtime environment. Every process runs with JAVA_HOME set and the JDK on the path. JAVA_TOOL_OPTIONS is the standard JVM mechanism for passing options without editing the launch command. Set it in the Secrets panel to tune the JVM (heap sizing, encoding, GC flags) and the JVM picks it up automatically. Anything else you set in the Secrets panel is available to the process at runtime.