NURL is a small, LLVM-backed systems language whose syntax is optimised for the way LLMs read and write code — fixed-arity prefix notation, a one-page LL(k≤4) grammar, and single-owner memory with a static borrow checker (on by default).
Driving an LLM agent? The compiler is also exposed as an MCP server — your assistant can build and run NURL directly.
Existing languages were shaped by human ergonomics. NURL drops the parts that exist only for humans and keeps what matters for correctness and compilation.
Every operator has a fixed arity — no infix, no precedence cliffs. About 50 grammar productions (Python has ~100, C ~200), parsed by recursive descent with at most 4 tokens of lookahead.
A token's meaning is derivable from a short window of preceding tokens. No long-range dependencies that break mid-generation.
Values auto-drop at scope exit. A static borrow checker (on by default) turns use-after-move, alias double-free, escaping closure captures, interprocedural/return escapes, loop-carried double-frees, and iterator invalidation into compile errors.
Identical source produces byte-identical output. No undefined behaviour, no platform-dependent semantics — the same program means the same thing everywhere.
The compiler emits LLVM IR and delegates codegen to clang. One pipeline reaches x86_64, ARM64, RISC-V, Xtensa, and wasm32-wasi — native speed by default.
The compiler is 17,232 lines of NURL. The bootstrap compiles it with itself twice and requires byte-identical LLVM IR on both rounds before a build is accepted.
Everything follows the same shape: OP ARG1 ARG2 …. No operator precedence to memorise, no parser surprises. Every snippet below compiles and runs against the current compiler.
// One line. No keywords.
@ add i a i b → i { ^ + a b }
// Calls use the same prefix shape.
( add 3 4 ) // → 7
@ fizzbuzz i n → v {
: ~ i i 1
~ <= i n {
: b d3 == 0 % i 3
: b d5 == 0 % i 5
? & d3 d5 { ( nurl_print `FizzBuzz\n` ) }
? d3 { ( nurl_print `Fizz\n` ) }
? d5 { ( nurl_print `Buzz\n` ) }
{ ( nurl_print_int i ) }
= i + i 1
}
}
// Tagged enum: sum type with payloads.
: | Expr {
Num i
Add *Expr *Expr
Mul *Expr *Expr
}
@ eval *Expr e → i {
^ ?? . e 0 {
Num n → n
Add l r → + ( eval l ) ( eval r )
Mul l r → * ( eval l ) ( eval r )
}
}
// Function-type literal: ( @ ret_ty arg_tys )
@ apply ( @ i i ) f i x → i { ^ ( f x ) }
// Closures capture locals.
: i n 5
: ( @ i i ) scale \ i x → i { * x n }
( scale 7 ) // → 35
( apply scale 9 ) // → 45
The full feature set goes well beyond these snippets: generics (including
over option types), traits with bounds, match guards, or-patterns, and
N-ary payloads, try-operator error handling, defer, channels with
select, compile-time const evaluation, and a stackful M:N
work-stealing async runtime — all exercised by the
477-program test suite.
Median wall-clock milliseconds across 5 runs, same algorithm per language. NURL compiles through LLVM -O2 and lands in Rust territory on compute-bound code.
| Benchmark | NURL | Rust 1.82 | Node v24 | Python 3.12 |
|---|---|---|---|---|
| lcg — 100M-iteration integer LCG | 10 ms | 16 ms | 9,680 ms | 27,459 ms |
| sieve — prime sieve | 69 ms | 62 ms | 142 ms | 5,898 ms |
| json_parse | 14 ms | 5 ms | 47 ms | 34 ms |
Intel Core i7-5930K, Ubuntu 24.04. Numbers are machine-specific — the suite is
reproducible with ./bench/run.sh; sources and full results live in
bench/.
Rust wins json_parse (serde is excellent); the point is the class,
not the trophy: compiled-language performance from a grammar an LLM can hold in
a few hundred tokens.
The compiler emits target-agnostic LLVM IR. Every platform below has been built and run — desktop and server targets are one click in the playground, and the embedded ports run on real silicon.
Embedded is real, not aspirational. A NURL HTTP file server runs on a Milk-V Duo — a $5 RISC-V board with 29 MB of RAM — cross-compiled as a static musl binary. On ESP32, NURL code flashed to an ESP32-D0WDQ6 drives GPIO directly through memory-mapped register writes, verified over serial; the RISC-V ESP32-C3/C6 family links with stock LLVM. Sources: duo/ and examples/esp32/.
The browser playground compiles to wasm32-wasi and runs the result
directly in your tab, and its /build_target endpoint cross-compiles
downloadable binaries for Linux (x86_64 / ARM64 / RISC-V), Windows, and macOS
(x86_64 + ARM64). The self-hosting compiler itself also builds to wasm, so the
entire toolchain can run in a sandbox.
Not stubs — production-hardened modules with their own test programs, leak-checked under AddressSanitizer.
Distributed systems (secure p2p overlay, STUN, NAT traversal, DERP relay, SWIM membership, CRDTs). HTTP/1.1 and HTTP/2, both client and server. WebSocket, MQTT 5.0, SMTP, Unix sockets, UDP, TCP/TLS.
JSON, TOML, YAML, XML, MessagePack, CBOR, and CSV with a unified serde layer. PostgreSQL (binary protocol, async, LISTEN/NOTIFY, COPY) and SQLite (transactions, WAL, authorizers) clients.
A stackful M:N work-stealing async runtime written in NURL, plus OS threads, mutexes, condition variables, channels with select, and atomics.
Vec, HashMap, OrdMap, BTree, LRU Cache, Bitset, exact fixed-point decimal, arbitrary-precision integers, regex, SHA-1/256/512, MD5, BLAKE3, gzip, tar, UUID, time, paths, processes, signals.
An Anthropic API client (streaming + tool use) and full MCP support — stdio and HTTP servers, client, sessions, registry. NURL programs can be agents and serve agents.
LSP server, VS Code extension, nurlpkg test/bench runner, tools/repl, nurldoc, nurlfmt formatter, --lint pass, DWARF debug info (--g), and a differential fuzzer.
The strongest claim a language can make is what's been shipped in it.
17,232 lines of NURL compile NURL. Every release must reproduce its own LLVM IR byte-for-byte through two self-compilation rounds — a fixed point, not a checksum.
Complete DMG emulation: passes Blargg's cpu_instrs and instr_timing, renders dmg-acid2 pixel-perfect, and plays Tobu Tobu Girl with the full 4-channel APU — compiled to wasm, running in your browser.
play.nurl-lang.org is a NURL program: HTTP server, build orchestration, the MCP endpoint, and the package registry — all served by the language's own stdlib.
From an Enigma machine and Game of Life to a distributed Push-To-Talk voice app, an HTTP/2 client, MCP servers, a Claude-powered agent, and a C64 emulator.
Four paths, in order of friction.
An online editor with examples, build, and run — everything compiles to WebAssembly and runs locally in your tab. Cross-compile downloads for six native targets included.
Open the PlaygroundDownload a prebuilt toolchain — compiler, package manager, and stdlib — for Linux (x86_64 / arm64), FreeBSD (x86_64) or Windows. No clang, no build. Then install programs straight from the registry.
curl -fsSL https://nurl-lang.org/install.sh | sh
export PATH="$HOME/.nurl/bin:$PATH"
nurlpkg install nq && echo '{"a":1}' | nq .a
irm https://nurl-lang.org/install.ps1 | iex
$env:Path = "$env:USERPROFILE\.nurl\bin;$env:Path"
nurlpkg install nq; echo '{"a":1}' | nq .a
The only build dependency is clang (LLVM 15+) — no Python, no make, no cmake. The build script bootstraps the self-hosting compiler twice and verifies byte-identical IR.
git clone https://github.com/nurl-lang/nurl cd nurl ./build.sh ./nurl.sh examples/fizzbuzz.nu && ./fizzbuzzView on GitHub
A VS Code / Windsurf extension lives under tooling/vscode-nurl/, backed by a real LSP server with diagnostics and references. The playground ships the same Monaco tokenizer.
NURL exposes the entire compiler toolchain as a hosted Model Context Protocol server. Any MCP-aware client — Claude Desktop, Claude Code, Cursor, Windsurf, Zed — can read the docs, browse examples, and build native or wasm binaries on your behalf. Nothing to install locally.
Add it as a remote MCP server in one command.
claude mcp add --transport http \ nurl https://play.nurl-lang.org/mcp
Drop into the client's mcpServers block.
{
"mcpServers": {
"nurl": {
"type": "http",
"url": "https://play.nurl-lang.org/mcp"
}
}
}
Open Settings → Connectors → Add custom connector and paste the URL above. Streamable HTTP transport, no auth needed.
Open connectors →nurl_coding_assistant primes the model with the grammarPointers into the repository for the curious.
A complete tour of the language, runtime, and pipeline — the canonical reference document.
EBNF spec lives in spec/grammar.ebnf. Historical snapshots track the language's evolution.
Every release documented in Keep-a-Changelog format with the reasoning behind each fix — currently at v0.10.3.
What's done, what's next. Maintained alongside the source so it doesn't drift from reality.