Home · ← SuperJ Manual EN|中文

Getting Started with SuperJ

What SuperJ is

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 — classes, interfaces, generics, enums, exceptions — and get a single self-contained native binary with no JVM, no JIT warm-up, and no garbage collector.

It is not a subset of Java. It keeps the parts of Java that make it pleasant and productive, drops the parts that fight against predictable native performance, and adds a layer of systems-level capability that Java doesn't have. The result reads like Java but behaves like C — hence super Java.

Why "super", not "subset"

A subset would only take away. SuperJ takes away and gives back:

Kept — the good parts of Java Classes and interfaces, single inheritance with multiple interfaces, generics (bounded type parameters, wildcards, the diamond <>), enums (with per-constant bodies), instanceof pattern matching with flow scoping, method references (::), varargs, try/catch/finally, @Override, the full operator and control-flow set, and a familiar String/collections feel.

Dropped — the parts that fight native performance or determinism Threads, locks, synchronized, volatile, java.util.concurrent (SuperJ is single-threaded by design — scale with processes, not threads); reflection, ClassLoader, and JPMS modules (everything is resolved at compile time); lambdas and non-static inner classes (no hidden closure machinery — method references and static nested classes cover the ground); autoboxing and checked exceptions; finalize().

Added — the modern, systems-level upgrades plain Java lacks

Design philosophy

Einstein is credited with the line that any smart fool can build a complex system, but it takes a real genius to make a system as simple as possible — and no simpler. SuperJ's design is the working-out of that principle for one language. The industry "obvious goods" — threads for concurrency, a borrow checker for safety, source-level ecosystem integration — are each a complex solution to a real problem, and in each case a simpler solution exists that removes the problem instead of managing it:

In each case the complex solution is what you reach for when you assume the problem must be managed; the simpler solution is what you get when you notice the problem can be removed. Complexity isn't just harder to use — it's where the undecidable bugs, the nondeterminism, and the monolingual lock-in live. Simpler isn't just nicer; it's more likely to be correct. The four principles below are the concrete instances of that idea.

  1. Single-threaded determinism. Removing concurrency isn't a limitation — it's the point. One event-loop thread per process means no locks, no data races, no scheduler jitter, and code you can reason about. Scale out with processes (SO_REUSEPORT), not shared-memory threads.
  2. No GC, no pauses. Arena allocation reclaims memory deterministically. The measured payoff is a near-flat latency curve: the HTTP server holds p99 ≈ p50 under load — the kind of tail behavior GC'd JVMs chase with great effort.
  3. Native performance is the baseline. AOT compilation to LLVM, zero- allocation hot paths, and the systems SDK put SuperJ in the same class as the fastest published frameworks — the plaintext HTTP server out-throughputs the fastest published TechEmpower plaintext champions on equal hardware, while running a full HTTP parse per request.
  4. Familiarity lowers the cost of all the above. A Java developer is productive immediately; the new capabilities are opt-in, not prerequisites.

Install

SuperJ installs in one command. The only host prerequisite is a C linker (clang); everything else ships in the package. The installer auto-detects and auto-installs missing dependencies (OpenSSL, PCRE2, zstd, lz4) via your platform's package manager.

One-line install (replace <download-url> with the URL you were given):

curl -fsSL <download-url>/install.sh | sh -s -- <download-url>

This downloads the installer, checks and auto-installs dependencies, fetches the tarball + checksum for your OS/arch, verifies it, extracts to ~/superj, and sets SJ_HOME and PATH in your shell profile (bash/zsh/fish, detected automatically). It also runs a link verification test (compiles a tiny C program against -lcrypto) to confirm the toolchain can produce executables. Idempotent — safe to re-run. Open a new shell, then:

superj --help

Verifying your installation

After installing, run superj doctor to confirm everything is ready to build:

superj doctor

This checks that clang, OpenSSL, PCRE2, zstd, and lz4 are available, runs a link test (compile + link a C program with the same flags superj build uses), and scaffolds + builds a tiny test project end-to-end. If anything is missing, it prints the exact install command for your platform.

SDK variants

SuperJ ships in three flavours that differ in how the SDK is delivered. Pass --sdk-variant (default community):

curl -fsSL <download-url>/install.sh | sh -s -- <download-url> --sdk-variant=community     # archive link (default, fastest compile)
curl -fsSL <download-url>/install.sh | sh -s -- <download-url> --sdk-variant=enterprise    # whole-program -O3 (best runtime perf)
curl -fsSL <download-url>/install.sh | sh -s -- <download-url> --sdk-variant=vip           # full SDK sources (audit/modify)

The three variants:

VariantWhat you getLink pathTradeoff
community (default)Prebuilt static archive + stubscompiler links the archive; clang links the final binaryFastest link; no cross-module whole-program optimization. Smallest install.
enterprisePrecompiled SDK module + objects + stubscompiler links the SDK with your program and optimizes the whole thingWhole-program optimization across SDK + user code (global inlining, dead-code elimination); slower link, better runtime perf.
vipSDK source (.sj files, no prebuilt artifacts)compiler compiles SDK + your sources together (--sdk-source); clang linksMaximum optimization + full source for audit/modification; slowest build.

The SDK source tree (sdk/sj/) ships only in the VIP install. Community and enterprise don't ship SDK source — they ship prebuilt artifacts (the archive for community, the compiled sdk.ll for enterprise) plus sdk/stubs/ (signature-only declarations the type-checker uses). So --sdk-source works only on a VIP install; on community/enterprise use --sdk-path (archive link) or --sdk-path … --enterprise (whole-program LTO via sdk.ll).

Your code is identical across all three — superj compile auto-detects the installed mode from $SJ_HOME/sdk, so you normally don't think about it:

superj compile app.sj                 # auto-detect the installed mode, emit IR
superj compile app.sj --link          # … and link an executable (always -O3)
superj compile app.sj --link --enterprise   # force whole-program LTO (needs enterprise SDK)

superj compile --link always passes -O3 to clang (unless --debug). Explicit --sdk-path <dir> (community + enterprise), --sdk-source <dir> (VIP only), and --enterprise override auto-detection. A program that imports nothing from sj.* is fully standalone — no SDK is linked at all.

Optimization flags

FlagEffect
(default)-O3 — always, unless --debug
--enterpriseWhole-program LTO: link the SDK with your program and optimize the whole thing
--no-bounds-checkDisable array bounds checks (hot numeric loops; ~1.1-1.5x speedup)
--simd <level>sse2 (default, x86), avx2 (x86 256-bit), none (disable). ARM NEON is always on (flag is a no-op).
--target-cpu <cpu>clang -mcpu=<cpu> (e.g. native, apple-m2)
--debug-O0 -g (1:1 debug line mapping; no optimization)

Maximum performance:

superj compile app.sj --sdk-path "$SJ_HOME/sdk" --enterprise --link \
    --no-bounds-check --simd avx2 --target-cpu native --output app
# or via the build system:
superj build --release --enterprise

On a VIP install (SDK source available), use --sdk-source instead of --sdk-path:

superj compile app.sj --sdk-source "$SJ_HOME/sdk/sj" --enterprise --link \
    --no-bounds-check --simd avx2 --target-cpu native --output app

Which variant am I using?

Check what's in $SJ_HOME/sdk/build/:

ls $SJ_HOME/sdk/build/

Switching variants means re-running the other installer.

Hello, SuperJ

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

superj new myapp        # scaffold: Build.sj + src/myapp/Main.sj + .gitignore
cd myapp
superj run               # compile + link + run in one step

You should see:

Hello from myapp

The scaffolded project:

myapp/
  Build.sj            ← manifest (name, version, entry, dependencies)
  .gitignore          ← ignores target/
  src/myapp/Main.sj   ← package myapp; class Main { public static void main(String[] args) { ... } }

Edit src/myapp/Main.sj:

package myapp;

public class Main {
    public static void main(String[] args) {
        System.out.println("hello from superj");
    }
}

Then:

superj run               # rebuild + run
superj build --release   # optimized build -> target/release/myapp
superj check             # whole-project type-check (no compile/link)

For the full build-system surface — Build.sj manifest fields, path and git dependencies, workspaces, profiles, build hooks, feature flags, superj add, superj clean, superj test — see The Build System.

Using the SDK

The SuperJ SDK ships in the package at $SJ_HOME/sdk/. A program that imports sj.* classes (collections, HTTP, JSON, SEDA, crypto, …) compiles against the installed SDK automatically — no flags needed:

superj run               # auto-detects the installed SDK mode

To see the full SDK API surface — every class, method, and signature in one file — run superj sdk-api (it prints to stdout; redirect to a file if you want to keep it). For a single class:

superj doc sj.http.Router            # print Router's methods + signatures
superj doc sj.util.IntArrayList      # print IntArrayList's surface
superj doc --list                    # print every SDK class (FQN + tag)

A curated set of demo programs covering the language surface and all SDK capabilities ships under $SJ_HOME/demo/ — browse it for a capability (http, json, seda, collections, …), read one demo, and you have the pattern.

IntelliJ plugin (optional)

SuperJ ships an optional IntelliJ IDEA plugin (syntax highlighting, Go-to-Declaration, run configuration). The plugin is not required to use the compiler — it's an IDE convenience only. Some distribution tarballs bundle the prebuilt plugin jar under $SJ_HOME/plugins/intellij/; if yours doesn't (or you want to build it yourself), see the contributor documentation in the source repository for build and install steps.

Where to go next

SuperJ — manual · generated from getting-started.md at pack time EN|中文