A language that takes correctness seriously.
NL is a statically typed, class-based language with native null safety, checked exceptions and exhaustive matching — compiled to compact bytecode and run by nlvm, a lightweight virtual machine written in Rust.
$ curl -fsSL https://nlvm.dev/install.sh | bash
01Why NL
Whole classes of bugs, caught before your program runs
Familiar C-family syntax, but the compiler is on your side: nullability, error handling and case analysis are part of the type system, not conventions.
◆Null safety, built in
Types are non-nullable unless you say otherwise. string|null is a real union type, and the compiler rejects unchecked use — with ?? and ?: to handle the null case in one expression.
string|null name = null;
system.Out.println(name ?? "anonymous");
int|null port = readPort();
int actual = port ?? 8080;
◆Errors you can't ignore
Checked exceptions: a method that can fail declares throws, and callers must catch or declare. Every exception carries a full stack trace, captured by the VM.
public static string load(string path)
throws IOException {
return system.io.File.readAllText(path);
}
try {
system.Out.println(load("config.txt"));
} catch (IOException ex) {
system.Err.println("Error: " + ex.message);
}
◆Exhaustive matching
match over an enum must cover every case — add a variant later and the compiler points at every match you forgot to update.
enum Color { Red, Green, Blue }
string name = match(c) {
Color.Red: "red",
Color.Green: "green",
Color.Blue: "blue",
};
◆Functions are values
First-class function types with explicit signatures — including throws — plus closures and type inference with auto.
(int, int) => int add = (int a, int b) => a + b;
auto eight = add(3, 5);
(string|null) => int throws Exception len =
(string|null s) => throws Exception {
if (s == null) {
throw new Exception("null");
}
return s.length();
};
◆One binary, one file
nlc compiles your whole program into a single .nlp file. The VM is one dependency-free Rust executable. Ship both, done.
$ nlc Main.nl -o Main.nlp
$ nlvm Main.nlp
Hello, world!
◆Specified and tested
The language is defined by a versioned, public specification — nlvm-specs — and the implementation tracks it release by release, backed by a YAML conformance suite run in CI.
$ nlvm --version
nlvm 0.23.0 (nlvm-specs 0.8.48)
$ nltest tests/
232 passed, 0 failed, 232 total
02Dogfooding
03Under the hood
A compiler and a VM, built as one toolchain
One Rust workspace, eight crates. The bytecode format is a single shared definition between compiler and VM, so the two halves can never drift apart.
04Devlog
Built in the open, written up as it goes
Design decisions, dead ends and release notes — the story behind the toolchain, straight from the workbench.
Proving parallelism in a browser tab: the HTTP server demo
One OS thread per connection, a mutex-guarded shared Server instance, and a "fire 5 parallel requests" button that turns real concurrency into something you can watch happen.
Teaching the VM to remember: stack traces & StackOverflowException
How exceptions gained real stack traces — a line-number table in the bytecode, a shadow call stack in the VM, and the subtle art of not tracing your own constructor.
July 2026 · releases 0.1.0 → 0.5.0From spec to running VM: the initial build
One Rust workspace, a vertical-slice strategy, and a YAML test runner driving development from day one — phase by phase, up to a single-file program format.
Ready to try it?
Clone, build with Cargo, and run your first program in under a minute.