Get Started

Hello, SuperJ

SuperJ is a systems programming language with Java's syntax, compiled ahead-of-time to native code through LLVM. You write what looks like ordinary Java and get a single self-contained native binary — no JVM, no JIT, no garbage collector. This walk takes you from install to a running web server in a few minutes.

Before you start

  • The installer auto-installs clang/LLVM 22.x and the other prerequisites via your platform package manager. Pass --no-deps if you prefer to manage those yourself. No JVM, no JIT, no runtime to install alongside it.

Targets. macOS arm64 (kqueue), Linux x86_64 and aarch64 (epoll). The community distribution is a prebuilt tarball — no build step required.

1

Install

Run the one-liner from the Download page. The installer auto-detects your platform, installs any missing dependencies (including clang/LLVM 22.x), downloads and verifies the tarball, extracts to ~/superj, and wires up SJ_HOME and PATH in your shell profile.

terminal
curl -fsSL https://superj.dev/releases/v1.3/install.sh | sh -s -- https://superj.dev/releases/v1.3

Open a new shell (or source your profile) so the new SJ_HOME/PATH take effect. Pass --no-deps to skip the dependency auto-install, or --prefix=/opt/superj to install elsewhere.

2

Verify

Check the version, then scaffold and run a project.

terminal
superj --version        # 1.3.0 (community)
3

Scaffold a project

SuperJ has a Cargo-inspired build system built into the superj binary. One command scaffolds a project; two more build and run it.

terminal
superj new myapp
cd myapp
superj run          # Hello from myapp
myapp/
  Build.sj ← manifest (name, version, entry, dependencies)
  .gitignore ← ignores target/
  src/myapp/Main.sj ← package myapp; class Main { … }
4

Write some SuperJ

Edit src/myapp/Main.sj. It looks like Java — but arena is a keyword, and there's no GC underneath.

src/myapp/Main.sj
package myapp;

public class Main {
    public static void main(String[] args) {
        int total = 0;
        arena scratch {
            int[] rows = new int[1 << 16];
            for (int i = 0; i < rows.length; i++)
                total += (rows[i] = i * 3);
        }   // scratch dropped here — O(1), no pause
        System.out.println("total = " + total);
    }
}
terminal
superj run              # rebuild + run
superj build --release  # optimized build → target/release/myapp
superj check            # whole-project type-check (no codegen/link)
superj test             # run the unit-test suite
5

Write a web server

The same SDK stack that powers the 515K req/s benchmark is one handler and one main away. Compile it to a single native binary — no framework, no runtime to install alongside it.

sj/demo/WebServer.sj
package sj.demo;
import sj.http.*; import sj.net.*; import sj.util.ByteArray;

class HelloHandler implements HttpRequestHandler {
    private final ByteArray response;
    HelloHandler() {
        String body = "Hello from SuperJ!\n";
        this.response = new ByteArray(
            "HTTP/1.1 200 OK\r\nContent-Length: "
            + body.length() + "\r\n\r\n" + body);
    }
    public void handle(HttpRequest r, SessionWriter w) {
        this.response.rewind();
        w.write(this.response);
    }
}

public class WebServer {
    public static void main(String[] args) {
        int port = 8080;
        if (args.length > 0) { port = Integer.parseInt(args[0]); }
        NioConfig cfg = new NioConfig(65536, 16384, 64, 262144, true, 1024);
        NioAdapter adapter = new NioAdapter(cfg);
        adapter.open("127.0.0.1", port, new HttpSessionProvider(new HelloHandler()));
        System.out.println("listening on http://127.0.0.1:" + port + "/");
        while (true) { adapter.poll(0); }
    }
}
terminal
superj compile sj/demo/WebServer.sj --sdk-path "$SJ_HOME/sdk" --link --output webserver
./webserver 8080
# in another terminal:
curl http://127.0.0.1:8080/    # → Hello from SuperJ!
6

Scale across cores

Single-threaded doesn't mean single-core. The true in NioConfig is reusePort — run several copies on the same port and the kernel balances incoming connections across them. No code change.

terminal
for i in 1 2 3 4; do ./webserver 8080 & done