π Node4J: Call Java from Node.js Like Native JavaScript (Py4J for JS)
Java has one of the richest ecosystems in software history.
Node.js has one of the most productive developer experiences.
But until now, bridging the two cleanly has been painful.
Thatβs why I built Node4J β a modern, TypeScript-first JVM bridge for Node.js, inspired by Py4J, but designed for the JavaScript world.
With Node4J, you can:
Call Java objects as if they were JavaScript objects
Execute Java JAR files directly from Node.js
Manage JVM lifecycle using worker threads
Build hybrid Java + Node systems without JNI or rewriting code
π€ Why Node4J?
If youβve ever faced one of these situations, Node4J is for you:
You have existing Java services or libraries and want to reuse them in Node.js
You want to expose Java business logic to a modern Node API
You want Py4J-like power, but for JavaScript
You need robust JVM process management from Node.js
You want type safety, async/await, and clean APIs
β¨ What Node4J Can Do
Core Features
π Connect to a running JVM (GatewayServer)
π§ Interact with Java objects directly from Node.js
βοΈ Execute Java JAR files from Node using worker threads
π Auto-restart JVM on crash
π§΅ Non-blocking JVM execution (Worker Threads)
π‘ Real-time stdout / stderr monitoring
π§© Fully async & Promise-based API
π§ͺ TypeScript-first with typed events
π¦ Installation
npm install node4j
π§ How It Works (Conceptually)
Node.js
β
βββ Node4J Gateway (TypeScript)
β
βββ Worker Thread
β βββ JVM Process (java -jar ...)
β
βββ Java GatewayServer (Py4J)
This design ensures:
JVM crashes donβt crash Node.js
Heavy JVM logs donβt block the event loop
Multiple JVMs can be managed safely
π Option 1: Connect to an Existing Java Gateway
Java Side (Server)
Node4J uses Py4J on the Java side.
Add dependency (Maven)
<dependency>
<groupId>net.sf.py4j</groupId>
<artifactId>py4j</artifactId>
<version>0.10.9.9</version>
</dependency>
Sample Java App
public class SampleJavaNode {
private Stack stack = new Stack();
public Stack getStack() {
return stack;
}
public static void main(String[] args) {
GatewayServer server = new GatewayServer(new SampleJavaNode(), 25333);
server.start();
System.out.println("Gateway Server started on port 25333");
}
}
Node.js Side (Client)
import { Gateway } from "node4j";
const myJava = new Gateway({
host: "127.0.0.1",
port: 25333,
});
const stack = await myJava.entryPoint.getStack();
await stack.push("Hello from Node.js");
console.log(await stack.pop());
const random = await myJava.jvm.java.util.Random();
console.log(await random.nextInt(10));
const system = await myJava.jvm.System;
console.log(await system.currentTimeMillis());
π‘ Yes β this is real Java code being executed.
π₯ Option 2: Execute Java JAR Files Directly from Node.js
This is where Node4J goes beyond Py4J.
π§΅ WorkerJarExecutor (Production-Grade JVM Launcher)
Node4J includes a WorkerJarExecutor, which:
Runs JVM in a worker thread
Detects when the JAR is βreadyβ
Restarts JVM on crash
Streams logs safely
Prevents zombie processes
Example: Launch a JAR from Node.js
import { Gateway, WorkerJarExecutor } from "node4j";
const executor = new WorkerJarExecutor();
await executor.start({
jarPath: "sampleJavaNode-1.0-SNAPSHOT.jar",
javaOpts: ["-Xmx512m"],
readySignal: "Gateway Server started on port 25333",
timeoutMs: 5000,
restartOnCrash: true,
maxRestarts: 3,
onMessage: (message) => {
switch (message.type) {
case "stdout":
console.log(message.args);
break;
case "stderr":
console.error(message.args);
break;
case "ready":
console.log("JVM is ready");
break;
}
},
});
Once started, you can connect using Gateway as usual.
π‘ Typed Worker Events (TypeScript-First)
Node4J uses typed event messages:
type WorkerMessage =
| { type: "stdout"; args: string }
| { type: "stderr"; args: string }
| { type: "exit"; args: string }
| { type: "shutdown"; args: string }
| { type: "ready"; args: string };
This gives you:
IDE autocomplete
Exhaustive switch checks
Safer production code
π‘ Why This Is Powerful
Compared to Alternatives
Approach Problems
REST / HTTP Serialization overhead
JNI Unsafe, complex
CLI execution Hard to manage lifecycle
node-java JVM embedded, harder to isolate
Node4J gives you:
β
Isolation
β
Safety
β
Scalability
β
Familiar JS APIs
β
Production readiness
π§ Use Cases
π’ Enterprise Java + Node microservices
π Gradual migration from Java to Node
π Analytics / ML Java libraries from Node
π₯οΈ Desktop apps (Electron + JVM)
β‘ High-performance JVM compute from JS
π£ Roadmap
JVM Worker Pool (multiple JVMs)
Autoscaling JVM executors
Health metrics (CPU, RAM, GC)
Distributed JVM execution
Cloud-native orchestration
β€οΈ Final Thoughts
Node4J brings Py4J-level JVM power to the JavaScript ecosystem, with modern Node.js design principles.
If you work with Java + Node, this library can save you months of effort.
π GitHub: https://github.com/umbrashia/node4j
π npm: npm install node4j
If you like the idea, Iβd love feedback, issues, and contributions.
Letβs bridge the JVM and JavaScript worlds π
Top comments (0)