DEV Community

Cover image for Node4J β€” Call Java Code Natively from Node.js
Shantanu Sharma
Shantanu Sharma

Posted on

Node4J β€” Call Java Code Natively from Node.js

πŸš€ 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>
Enter fullscreen mode Exit fullscreen mode

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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;
    }
  },
});
Enter fullscreen mode Exit fullscreen mode

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 };
Enter fullscreen mode Exit fullscreen mode

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)