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, Find Usages, structure view, run configuration). The plugin is not required to use the compiler — it's an IDE convenience only.

Install once, then get every future update automatically via a custom plugin repository: in IntelliJ, go to Settings -> Plugins -> gear icon -> Manage Plugin Repositories -> + and add the SuperJ plugin repository URL (distributed with each release's notes). Then search for SuperJ under Marketplace (it now lists this repository too) and install it, or use Check for updates if you already have an older copy installed. No IntelliJ SDK, JDK, or manual jar-copying required — this is the same path a normal plugin update takes.

If you'd rather build the plugin from source yourself, see the contributor documentation in the source repository for the manual build and install steps.

Where to go next

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