# How to run Java code in a sandbox Install an OpenJDK from Ubuntu in an isolated Linux microVM, write the `.java` file, and run it with `java` under a timeout. **On Runtime, Java takes one apt command, or none in an image you build once, and a single-file program needs no separate compile step.** Every sandbox is a Firecracker microVM with its own kernel and `sudo`. The code interpreter runs Java cells too, keeping variables between them; on 23 September 2026 its first Java cell installed Java from Ubuntu's archive in about 35 seconds, once per sandbox ([code interpreter](/docs/javascript#code-interpreter)). A 2 vCPU, 4 GiB sandbox costs $0.03125 an hour while it waits and $0.08 with both CPUs busy ([pricing](/docs/pricing)). ## Which JDK to install Ubuntu 24.04's archive, read on 25 September 2026: | Package | Version | Notes | | ------------------------- | --------- | ----------------------------------------------- | | `openjdk-21-jdk-headless` | 21.0.12.1 | Java 21 LTS without GUI libraries; main archive | | `default-jdk-headless` | Java 21 | Points at OpenJDK 21 | | `openjdk-25-jdk` | 25.0.4.1 | Java 25, from the universe archive | | `maven` | 3.8.7 | Maven, from the universe archive | | `gradle` | 4.4.1 | An old Gradle; use your project's `./gradlew` | The headless JDK leaves out the GUI libraries, which a command-line program does not need, and so takes less of the default 4 GiB disk. ## Install Java and run a program Since JDK 11 the `java` launcher runs a program given as one source file, with no `javac` step ([JEP 330](https://openjdk.org/jeps/330)): ```ts check import { Sandbox } from "withruntime"; const source = ` import java.util.stream.IntStream; public class Main { public static void main(String[] args) { int n = Integer.parseInt(args[0]); System.out.println(IntStream.rangeClosed(1, n).sum()); } } `; await using sbx = await Sandbox.create({ timeoutSeconds: 900, onLeaseEnd: "stop" }); await sbx.exec( "sudo apt-get update -q && sudo apt-get install -y -q --no-install-recommends openjdk-21-jdk-headless", { check: true, timeoutMs: 600_000 }, ); await sbx.network.set({ internet: false }); // the program runs offline await sbx.files.write("/workspace/Main.java", source); const run = await sbx.exec(["java", "Main.java", "100"], { timeoutMs: 60_000 }); console.log(run.exitCode, run.stdout); // 0 5050 ``` ```python check from withruntime import Sandbox source = """ import java.util.stream.IntStream; public class Main { public static void main(String[] args) { int n = Integer.parseInt(args[0]); System.out.println(IntStream.rangeClosed(1, n).sum()); } } """ with Sandbox.create(timeout_seconds=900, on_lease_end="stop") as sbx: sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q --no-install-recommends " "openjdk-21-jdk-headless", check=True, timeout_ms=600_000) sbx.network.set(internet=False) # the program runs offline sbx.files.write("/workspace/Main.java", source) run = sbx.exec(["java", "Main.java", "100"], timeout_ms=60_000) print(run.exit_code, run.stdout) # 0 5050 ``` - The argument after the file name reaches `main` as `args[0]`. An array runs `java` directly, so no shell reads it. - Compile errors come back on `stderr` with a non-zero exit code. - A program that never ends returns `timedOut: true` with what it printed. For several files, compile them with `javac -d out $(find src -name '*.java')` and run `java -cp out Main`. ## A Java notebook The interpreter keeps a Java context's variables between cells, like a notebook: ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create(); await sbx.interpreter.run("record Item(String name, double price) {}", { language: "java" }); await sbx.interpreter.run( 'var items = java.util.List.of(new Item("pen", 1.5), new Item("pad", 3.25));', { language: "java" }, ); const cell = await sbx.interpreter.run("items.stream().mapToDouble(Item::price).sum()", { language: "java", }); console.log(cell.results[0]?.data["text/plain"]); // 4.75 ``` ```python check from withruntime import Sandbox with Sandbox.create() as sbx: sbx.interpreter.run("record Item(String name, double price) {}", language="java") sbx.interpreter.run('var items = java.util.List.of(new Item("pen", 1.5), new Item("pad", 3.25));', language="java") cell = sbx.interpreter.run("items.stream().mapToDouble(Item::price).sum()", language="java") print(cell["results"][0]["data"]["text/plain"]) # 4.75 ``` The first Java cell installs the JDK from Ubuntu's archive, so leave the internet on for it, or use an image that already has Java. ## A Maven or Gradle project Upload the project, let the build tool fetch its dependencies, then run the tests with the network off: ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ image: "java", diskMiB: 8192, timeoutSeconds: 3600, onLeaseEnd: "stop", }); await sbx.files.upload("./my-service", "/workspace/app"); await sbx.exec("mvn -q -B dependency:go-offline", { cwd: "/workspace/app", check: true, timeoutMs: 900_000, }); await sbx.network.set({ internet: false }); const test = await sbx.exec(["mvn", "-B", "-o", "test"], { cwd: "/workspace/app", timeoutMs: 1_800_000, onStdout: (text) => process.stdout.write(text), }); console.log("exit", test.exitCode); ``` For Gradle, run the project's own wrapper (`./gradlew test`) rather than Ubuntu's Gradle 4.4.1. ## Java in every sandbox ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build({ name: "java", recipe: { apt: ["openjdk-21-jdk-headless", "maven"] } }); await using sbx = await runtime.sandboxes.create({ image: "java", network: { internet: false } }); console.log((await sbx.exec(["java", "-version"])).stderr); ``` ```python check from withruntime import Runtime runtime = Runtime() runtime.images.build(name="java", recipe={"apt": ["openjdk-21-jdk-headless", "maven"]}) with runtime.sandboxes.create(image="java", network={"internet": False}) as sbx: print(sbx.exec(["java", "-version"]).stderr) ``` The same image serves the code interpreter: a Java cell in a sandbox made from it starts without installing anything. Building an image is free; a stored image is charged on its size ([custom images](/docs/images)). ## Related - [Run Kotlin code in a sandbox](/languages/kotlin) - [Grade student code](/use-cases/grade-student-code) - [Build a code interpreter for a chatbot](/use-cases/code-interpreter-for-chatbots) - [Run Go code in a sandbox](/languages/go) New accounts get 50 free sandbox hours, no card: ```bash no-run npx withruntime sandbox run --trial -- bash -c 'sudo apt-get update -q && sudo apt-get install -y -q openjdk-21-jdk-headless && java -version' ``` ## Sources - JEP 330, launch single-file source-code programs (JDK 11): https://openjdk.org/jeps/330 (read 25 September 2026) - Ubuntu 24.04 package indexes (`openjdk-21-jdk-headless` 21.0.12.1+1-1~24.04.4, `openjdk-25-jdk` 25.0.4.1+1-1~24.04.4, `default-jdk-headless` 2:1.21-75+exp1, `maven` 3.8.7-2, `gradle` 4.4.1-20): http://archive.ubuntu.com/ubuntu/dists/noble-updates/ and http://archive.ubuntu.com/ubuntu/dists/noble/ (read 25 September 2026) Facts on this page were checked on 25 September 2026.