Fiji is a Java runtime for the WebAssembly component ecosystem.
Releases · Documentation · Changelog · Release manifest
0.4.x establishes a stable runtime and component contract.
0.5.x aims to make Java a first-class component language rather
than merely a guest running inside components.
Fiji is a Java Virtual Machine packaged as a WebAssembly component.
It exposes a public WIT contract (fiji:jvm/jvm@0.1.0) that lets a
host load .class bytes, invoke Java methods, exchange typed
values with Java objects, and tear the VM down — all without
linking against JNI or shipping a native libjvm.
A real Java runtime executes the bytecode.
Take the JARs and .class files you already have and run them on
Fiji. Fiji is an additional deployment target for Java code,
not a replacement ecosystem.
- Standard
javacoutput runs unchanged. Compile with any JDK 21+javacyou already have. - No Fiji compiler. No
javacwrapper, no Fiji-aware build step. - No annotations. No
@FijiExport, no@FijiEntryPoint, none of that. Your source is unchanged. - No bytecode rewriting. No agent, no instrumentation pass, no transformation of class files.
- No build plugin. No Maven plugin, no Gradle plugin. Use the plugins you already use.
If it builds on a normal JVM today and respects the boundaries in
dist/CONSTRAINTS.md, it runs on Fiji
tomorrow. Your existing Maven, Gradle, IDE, and CI
pipelines work as-is.
Compile once with standard Java tooling. Deploy the same artifact across browser, server, edge, and embedded environments. No per-target build, no runtime-specific variant, no second toolchain.
| Target | What runs |
|---|---|
| Browser | Same .wasm, transpiled for the browser via jco |
| Server | Same .wasm, run under standalone Wasmtime or any native component-model runtime |
| Edge | Same .wasm, on any Wasm-component-capable edge runtime |
| Embedded | Same .wasm, linked in-process via the Wasmtime crate (or any component-model implementation) |
The same Java bytecode, the same component artifact, the same
public WIT contract — across all four host categories. Tutorial 5
in the release tarball
(05-same-artifact-several-runtimes/)
demonstrates this end-to-end.
Most existing options for running Java in non-Java environments involve a tradeoff that loses something fundamental about Java:
- Compiling Java to a native binary (e.g. AOT image builds) loses the portability story — you get one binary per platform rather than one artifact that runs anywhere.
- Transpiling Java to Wasm directly loses semantic fidelity — reflection, dynamic class loading, and full classpath search rarely survive the translation cleanly.
- Embedding a native JVM via JNI loses the deployment story —
the host must link against
libjvmand ship platform-specific binaries.
Fiji's bet is different: keep a real JVM, package it as a WebAssembly component, and let the host talk to it through a typed WIT contract. The result is one artifact that runs in any component-capable host (wasmtime, jco, browsers via jco), preserves the semantics standard Java tooling already produces, and exchanges typed values with non-Java components without any JNI surface.
Pick Fiji when you want:
- Full Java semantics (real bytecode, real reflection) running in a component-capable host.
- A single artifact rather than per-platform native binaries.
- Typed cross-language interop with Rust, Python, or any other component-capable language — through a WIT contract, not JNI.
- Run Java workloads (any
.classfiles compiled by a standardjavac) inside a Wasm component runtime. - Exchange typed values (primitives, strings, arrays, object references) between Java and the host via the public WIT.
- Compose Fiji with other Wasm components — give Java code access to non-Java capabilities through component-model interfaces rather than JNI.
The release ships an end-to-end verification path that any consumer can run against their installation.
The fastest way to install Fiji and its required Wasmtime runtime:
curl -fsSL https://fiji.dev/install.sh | shThe installer detects whether a supported Wasmtime is already on
your PATH and only installs one if needed. If you'd rather manage
WebAssembly runtimes yourself, install Wasmtime
(wasmtime.dev) directly — Fiji works with
any installation method that puts wasmtime on PATH at a supported
version.
For users who want a dedicated WebAssembly runtime manager, we
recommend wvm. Fiji's installer
uses it when needed, but Fiji itself does not depend on it at
runtime: fiji doctor only checks for wasmtime.
After installation:
fiji --version # print release version
fiji doctor # diagnose whether the host has a supported Wasmtime
fiji verify-release # run the release verification floors
fiji manifest # emit MANIFEST.json
fiji wit # emit the public WITThe smallest end-to-end demonstration — a standard javac-produced
.class running inside a Wasm component:
// HelloFiji.java
public class HelloFiji {
public static void main(String[] args) {
System.out.println("Hello from Fiji.");
}
}javac --release 21 HelloFiji.java
wasmtime run --dir=. fiji-runtime-hotspot.component.wasm HelloFiji
# → Hello from Fiji.No Fiji-aware API. No annotations. Standard javac output, running
inside a WebAssembly component, producing the output you'd expect.
The release tarball ships two ready-to-run tutorials in
tutorials/:
01-hello-fiji— the example above, fully wired.05-same-artifact-several-runtimes— the same workload + same component artifact under multiple host categories (standalonewasmtime, Node viajco, with pointers to browser and embedded-library hosts).
Beyond running a Java application inside a component, Fiji can serve as the runtime behind a component package — a Java implementation exported through a non-Fiji WIT interface that consumers bind against without any awareness of Java or Fiji.
That is a different product surface from the runtime: Java becomes another implementation language for producing component-model packages, alongside Rust, C, Go, and the rest of the component-model ecosystem.
The first end-to-end demonstration lives in-repo:
crates/pkg-r-2-greeter-wrapper/— wrapper component that importsfiji:jvmand exportsexample:greeter.crates/pkg-r-2-greeter-consumer/— stranger Rust consumer that binds againstexample:greeteronly. Grep forfijiacross this crate returns zero matches.smokes/pkg-r-2-greeter-smoke.sh— mechanical acceptance check: composed component exportsexample:greeter, consumer carries no Fiji vocabulary, andgreet("World")returnsHello, World.
Walk-through: Tutorial 3 — Publish a Java library as a Wasm component.
The consumer-visible contract is clean today. The remaining frontier
is internalizing the JDK class image so the consumer needs zero
Fiji-side execution prerequisites; until that lands the consumer
preopens the image at /jdk via an env var. The contract surface is
unaffected.
- Public —
components/wit/fiji-jvm.wit. This is the contract. Consumers bind against the packagefiji:jvm@0.1.0and treat everything documented there as stable for the release line. - Internal — every other component, every other WIT file, all composition pins, and the runtime's internal layout. Treat as implementation detail; subject to change between releases.
Every release ships both boundaries of what runs on Fiji:
- Negative boundary —
dist/CONSTRAINTS.md: what does NOT fit. Short form: no AWT/Swing, no unrestricted native library loading, no unrestricted process spawning. Workloads that depend on those surfaces fail clearly at the boundary rather than silently degrading. - Positive boundary —
doctrine/envelope-0.4.md: what DOES fit, organized by category (execution hosts, Java features, networking, file I/O, encryption, composition, validated applications). Each row carries a ✓ / △ / ✗ classification with empirical evidence pointers. Use it to self-classify a workload before adopting Fiji.
0.4.x is the runtime-and-contract stabilization line. The
WIT contract, the artifact set, and the consumer surface are all
stable. New 0.4.x releases are bug fixes and forward-compatible
extensions; the contract itself is frozen against
fiji:jvm@0.1.0.
0.5.x will make Java a first-class component language. In
0.4.x Fiji is the runtime that runs a Java program inside a
component; in 0.5.x Java libraries themselves become consumable
WebAssembly components. The intent is that a Rust or Python
developer should be able to consume a Java component without
needing to know anything about Fiji internals — a Java library
appears as a typed component on equal footing with one written in
any other language.
The first end-to-end proof of this lives in 0.4.x already (see
the section above on publishing a Java library as a Wasm component);
the categorical move at the contract surface is demonstrated. The
remaining 0.5.x work is making the resulting artifact
self-contained — bundling the JDK class image into the component so
no consumer-side preopen is required.
Beyond 0.5.x, the trajectory continues into workflow bridges
(treating Java's traditional library ecosystem as bridges into the
component world rather than dead-ends outside it) and operational
hardening. Fiji is a platform for Java in the component world, not
an experiment.
Full documentation — tutorials, API reference, release notes, contributor doctrine — lives at tegmentum.github.io/fiji.
In-repo references:
CHANGELOG.md— chronological release logRELEASE_MANIFEST.md— current release manifest (SHA pins, artifact BOM, contract freeze record)dist/CONSTRAINTS.md— negative boundary (what does not fit)doctrine/envelope-0.4.md— positive boundary (what does fit, by category, with evidence)components/wit/fiji-jvm.wit— the public contract
The sections below are for contributors working in this source repository. Consumers running the Fiji release tarball generally need only the sections above.
| Top-level path | What lives here |
|---|---|
assets/ |
Brand assets (logo). Copied into the release tarball by the factory. |
build/ |
Wasm component build outputs (substrate, composed components). |
crates/ |
Rust crates — facade, runtime smoke harnesses, host bindings. |
dist/ |
Reference inputs for the release factory (e.g. CONSTRAINTS.md). |
docs/ |
Contributor design notes (legacy). Not shipped in the release tarball. |
doctrine/ |
Contributor doctrine — closure specs, design specs, evidence. Not shipped in the release tarball. |
website/ |
Docusaurus source for the public documentation site (deployed to GitHub Pages). |
experiments/ |
OpenJ9 and other research substrates. Out of the Fiji release train. |
release/ |
Assembled release artifacts (fiji-<version>/ directories + tarballs). |
scripts/build/ |
Release factory — package-release.sh is the entry point. |
smokes/ |
Build-time + release-time smokes that gate the release floors. |
tutorials/ |
Tutorial sources copied into release tarballs. |
upstream/ |
Vendored upstream sources (OpenJDK, etc.). |
./scripts/build/package-release.sh <VERSION>The factory enforces a deny-default consumer-vocabulary gate
(scripts/build/consumer-vocab-allowlist.txt is the audited
exception list), a provenance commit-timing cross-check, and floor
verification against manifests/MANIFEST.json. The architectural
invariant the factory operates under is documented at
doctrine/specs/release-artifact-is-not-a-repository-snapshot.md.
SUPPORT_SURFACE.md— historical legacy — describes a frozenfijivm-cli interpreter+JIT pathfrom earlier in the project; superseded by the post-#622 component pipeline. Kept for archive reference only.
Fiji is licensed under the GNU General Public License, version 2,
with the Classpath Exception (GPL-2.0-only WITH Classpath-exception-2.0)
to match the OpenJDK upstream it embeds and patches. The full text is in
LICENSE at the repository root.
Vendored upstream sources retain their original licenses:
| Component | Path | License |
|---|---|---|
| OpenJDK | upstream/jdk/ |
GPLv2 with Classpath Exception (upstream/jdk/LICENSE, upstream/ADDITIONAL_LICENSE_INFO, upstream/ASSEMBLY_EXCEPTION) |
| Eclipse OpenJ9 | experiments/openj9-wasm/openj9/ |
EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 (experiments/openj9-wasm/openj9/LICENSE) |
| Eclipse OMR | experiments/openj9-wasm/omr/ |
EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 (experiments/openj9-wasm/omr/LICENSE) |
Additional third-party notices (Unicode, MurmurHash3, libffi, zlib, CuTest,
Google Test, pugixml) are documented in the respective NOTICES.md /
NOTICE.md files under each vendored tree.
