Zuri

The language, its library and its whole toolchain, in one download

One language, one binary, the entire development lifecycle.

Stop learning an entire constellation of third-party tools just to build on the web.

Zuri ships a standard library that covers the whole stack, a JIT compiler, and every tool from the first line to the shipped app: a formatter, a test runner, a language server, a package manager, a package registry and a bundler.

$ curl -fsSL https://zuri-lang.github.io/zuri/install.sh | sh

Linux and macOS on x86-64 and ARM, and Windows on x86-64. zuri upgrade keeps it current. Installation guide

ada@laptop: ~/weather
~ $ zuri init weather --yes
  zuri init  weather 0.1.0

  added  project.toml
  added  index.zu
  added  app/index.zu
  added  tests/app.test.zu
  added  README.md
  added  .gitignore
  added  .gitattributes

  Your project is ready.
~/weather $ zuri install thermo
Resolving dependencies
Installing thermo 0.1.0
  + thermo 0.1.0
Installed 1 package.
~/weather $ zuri run
Hello, world!
~/weather $ zuri test

  zuri test  1 file in tests

   PASS   app.test.zu  41ms  2 tests

  1 file
  2 passed  •  2 total
  time 43ms
~/weather $ zuri fmt
Nothing to do. All 3 files are already formatted.
~/weather $ zuri bundle --format exe
Built /home/ada/weather/dist/weather-0.1.0-x86_64-unknown-linux-gnu
~/weather $ ./dist/weather-0.1.0-x86_64-unknown-linux-gnu
Hello, world!
In the box:
  • REPL
  • Tiered JIT
  • Standard library
  • Test runner
  • Formatter
  • Language server
  • Package manager
  • Package registry
  • Bundler
  • Self-update

The ecosystem tax

When you learn Zuri, you already know the stack.

Software creation has become buried beneath endless layers of glue code, external configs and shifting package ecosystems. Zuri brings the focus back to writing software: one cohesive platform, one documentation site, and zero framework fatigue.

When you pick up a modern language, you do not just learn that language. To serve a single web page or persist a record, you must research, evaluate and configure dozens of disconnected third-party libraries. Every piece comes from a different author, follows conflicting conventions, and keeps its own documentation in its own shape.

You spend twenty percent of your time learning core concepts and eighty percent wrestling with arbitrary tool churn.

Zuri removes that tax. The runtime, the server, the data layer and the utility toolchain were designed together and speak the same conceptual dialect.

  • Elsewhere, you assembleZuri ships
  • a package manager and a lockfilezuri install
  • an HTTP frameworkimport http
  • a database driver for each engineimport sql
  • a validation libraryimport validate
  • a template engineimport wire
  • a test runnerzuri test
  • a formatterzuri fmt
  • a language serverzuri lsp
  • a bundlerzuri bundle
  • a package registryzuri serve

The toolchain

Built in, not bolted on.

Every tool below ships inside the zuri binary, was designed alongside the language it serves, and is documented in the same book. Install once, and the whole lifecycle is a subcommand away.

Everything speaks the same dialect

This is a whole application.

Every import below is in the box: nothing was installed, nothing was resolved, nothing was configured.

signup.zu
import http
import validate
import log

var signups = validate.schema({
  name: validate.required().string().max_length(60),
  email: validate.required().string().email(),
})

var server = http.server(3000)

server.post('/signup', @(request, response) {
  var body = request.json_body() or {}
  var checked = signups.check(body)

  if !checked.valid {
    return response.json({ errors: checked.errors }, 422)
  }

  log.info('signed up ${body.email}')
  response.json({ ok: true }, 201)
})

server.listen()
ada@laptop: ~/signup
~/signup $ zuri run signup.zu
2026-10-09T21:43:40+01:00 INFO [signup]: signed up ada@example.com
another terminal
$ curl -X POST localhost:3000/signup -d '{"name":"Ada","email":"ada@example.com"}'
{"ok":true}

$ curl -X POST localhost:3000/signup -d '{"name":"Ada","email":"nope"}'
{"errors":[{"field":"email","message":"The email field must be a valid email address."}]}

There is one binary and the library that ships beside it. Zuri has first-class language-level support for package management and vendoring, so the code you bring in from outside needs no third-party tooling either.

Every module was built by the same hands. The naming is the same. The error types are the same. The documentation is one book.

Batteries included

The standard library is the framework.

Each program here runs exactly as shown, on a fresh install, with nothing added. The output beside it is what it printed.

shop.zu
import sql

var db = sql.open('sqlite://shop.db')

db.exec('create table orders (id integer primary key, item text, total real)')
db.insert('orders', { item: 'Kettle', total: 34.5 })
db.insert('orders', { item: 'Teapot', total: 21 })

for order in db.query('select * from orders where total > ?', [25]) {
  echo '${order.item}: ${order.total}'
}
output
Kettle: 34.5

SQLite, PostgreSQL, MySQL and MariaDB behind one interface, with pools, transactions, streaming and prepared statements. Changing engines means changing the connection string. Read more

The standard library

Crafted by the same hands.

Every module is reachable with a bare import, and every public name is documented in the standard library reference, generated from the library's own doc blocks.

The web
http server, client, HTTP/2, WebSocket wire templates html HTML5 parser, CSS selectors url mime
Mail
mail SMTP, IMAP and POP3, clients and servers
Networking
net TCP, UDP, TLS, DTLS, polling rpc JSON-RPC 2.0
Databases
sql SQLite, PostgreSQL, MySQL, MariaDB, pools, transactions
Data formats
json yaml toml csv struct base64 convert
Correctness
validate types enum
Security
crypto hash bcrypt jwt uuid
The machine
os env io args log stat date with the IANA time zones
Concurrency
isolate OS threads, separate heaps, channels
Numbers and collections
math array typed arrays set
Archives
compress gzip, zlib, deflate, bzip2, brotli, zstd, lz4, tar, zip
Images and colour
imagine decode, draw, filter, encode colors colour spaces, terminal colour
Interop
ffi C and Rust libraries, callbacks
Testing
test suites, expectations, mocks and spies
Metaprogramming
zuri lexer, parser, compiler, reflection

Because every one of them was designed together, moving between a database query, a hash and an HTTP response costs you no mental friction.

Ship it anywhere

Ship to machines that have never heard of Zuri.

zuri bundle packs your program, the packages it uses, the standard library and the runtime into one thing you can hand to anyone. It runs the same on every machine it lands on, with nothing to install first.

Single executableOne file to download and run. --format exe
macOS appA double-clickable application. --format app
ArchiveA .tar.gz, or a .zip for Windows.
DirectoryReady for a container image. --format dir
  • x86_64-unknown-linux-gnu
  • aarch64-unknown-linux-gnu
  • x86_64-apple-darwin
  • aarch64-apple-darwin
  • x86_64-pc-windows-msvc

Build for every one of them from the machine you are on with zuri bundle --target all. Single-file macOS bundles come out signed ad hoc, which is all an Apple silicon Mac needs to run them, and the book walks through Developer ID signing and notarization. Bundles and upgrades

ada@laptop: ~/weather
~/weather $ zuri bundle --format exe
Built /home/ada/weather/dist/weather-0.1.0-x86_64-unknown-linux-gnu

~/weather $ scp dist/weather-0.1.0-x86_64-unknown-linux-gnu server:weather

ada@server:~ $ zuri --version
bash: zuri: command not found

ada@server:~ $ ./weather
Lagos: 31°C, 87.8°F

Packages and Nyssa

Share code, and host it yourself.

When you share code, the package manager is already installed, and so is the registry it talks to.

ada@laptop: ~
~/thermo $ zuri publish
Publishing thermo 0.1.0 to https://pub.zurilang.org
Published thermo 0.1.0 (1.4 KiB, sha256:a682a47cda7a3a6bc9e4c2ee0ee5477b591d3030fa42d1cd305ff43d3b536e8d)

~/weather $ zuri install thermo
Resolving dependencies
Installing thermo 0.1.0
  + thermo 0.1.0
Installed 1 package.
  • One version of every package, resolved from version ranges into a lockfile that zuri restore reproduces exactly.
  • Every package command that changes a project shows exactly what it would do with --dry-run.
  • Packages carry commands, and globally installed tools land on your PATH.
ada@server: ~
~ $ zuri serve
Nyssa is serving http://127.0.0.1:3000
listening on 127.0.0.1:3000, storage in /home/ada/.zuri/nyssa
  • Nyssa is the registry in every installation: the API the package commands talk to, and a website for finding packages and reading their documentation.
  • SQLite with nothing to set up, or PostgreSQL, MySQL and MariaDB through the same connection strings sql opens.
  • Ready for production: HTTPS, accounts and tokens, closed sign-up, a read-only mode, live backups and archive checks.
Packages and Nyssa

Language design

Dynamic, and it declines to be vague.

Zuri takes the expressive, familiar syntax of modern dynamic languages and adds deliberate structural controls.

Zuri features true access controls with sealed classes, function parameter type guards, private methods and modules, all enforced by the compiler. The point of each is the same. The things that are hard to see when reading code are the things the language refuses to let you get wrong.

Every error names what went wrong, where, and the line it happened on, whether it surfaces in your editor, at compile time or while the program runs.

account.zu
class Account {
  @new(owner: string) {
    self.owner = owner
    self._balance = 0
  }

  deposit(amount: number) {
    self._balance += amount
    return self._balance
  }
}

var account = Account('ada')

Typed parameters are checked at the callaccount.deposit('50')

$ zuri run account.zu
Unhandled TypeError: deposit() expects parameter 'amount' (argument 1) to be a number, got string
  --> /home/ada/account.zu:7

  5 |   }
  6 | 
> 7 |   deposit(amount: number) {
  8 |     self._balance += amount
  9 |     return self._balance

Stack trace (most recent call last):
  at deposit() /home/ada/account.zu:7
  at @.script() /home/ada/account.zu:15

Classes are sealedaccount.nickname = 'countess'

$ zuri run account.zu
Unhandled PropertyError: undefined field 'nickname' on instance of 'Account'
  --> /home/ada/account.zu:15

  13 | var account = Account('ada')
  14 | 
> 15 | account.nickname = 'countess'

Stack trace (most recent call last):
  at @.script() /home/ada/account.zu:15

Private stays private, before a line runsecho account._balance

$ zuri run account.zu
SyntaxError: '_balance' is private and can only be accessed via 'self' or 'parent'
  --> /home/ada/account.zu:15:14
   |
15 | echo account._balance
   |              ^
account.zu
class Account {  @new(owner: string) {    self.owner = owner    self._balance = 0  }   deposit(amount: number) {    self._balance += amount    return self._balance  }} var account = Account('ada')account.deposit('50')TypeError deposit() expects parameter 'amount' (argument 1) to be a number, got string  account.mdeposit(amount: number)fownermto_string()

Editor support

Your editor already speaks Zuri.

zuri lsp is a full language server, written in Zuri on the compiler's own parser, so what it reports is what the runtime would do with the same code.

  • CompletionMembers, names in scope and module exports, with the import added for you.
  • Diagnostics as you typeWith the runtime's own messages, and quick fixes beside them.
  • NavigationDefinitions, references, implementations, call and type hierarchies.
  • RefactoringRename across the workspace, extract and inline variables and functions.
  • Hover and signaturesDocumentation laid out the way the reference lays it out.
  • Tests and formattingRun a test from the line it is on, and format a file or a selection.

Performance

Fast, without being asked.

A fast Just-In-Time compiler driven underneath by Cranelift, the same engine that drives wasmtime, with cutting edge specialization and optimized to production workloads. The tiering happens on its own, on background threads, with no annotations and no flags.

  1. The interpreter

    Your program starts at once, as bytecode, and every function begins here while the runtime watches what is hot.

  2. Kebbi

    The quick compiler turns a hot function into machine code that keeps values in registers, proving what it can about types before it compiles.

  3. Bayelsa

    The optimizing compiler builds the function as a graph of typed values, builds small functions into their callers, moves checks out of loops and bets on what the code has done so far.

Compiles never block

Both compilers run on background threads. A program carries on in the code it already has until the faster code is ready.

Every core, safely

Isolates run on real OS threads with heaps of their own, so parallel work needs no locks and shares no state by accident.

Native when it matters

Call straight into C and Rust libraries through ffi when a hot path already exists in native code.

Performance and the JIT

Roadmap

Already here, and what comes next.

Already here

  • The language, complete and self-hosting enough to parse, compile and reflect on itself
  • A tiered Just-In-Time compiler
  • A standard library covering the whole stack
  • SQLite, PostgreSQL, MySQL and MariaDB behind one interface
  • A test runner and a formatter
  • A language server for every editor
  • Package management built into the runtime
  • Nyssa, a self-hosted package registry in every installation
  • Bundles that run where Zuri is not installed
  • C and Rust interop
  • Two books, one of them generated from the library itself

AI involvement, on the record

AI wrote code in this repository, and how much, where, and how well it went are documented rather than glossed over. AI.md is that account, and it ends in a rule that contributors are held to.

Read AI.md

The whole platform, one command away.

One command installs the runtime, the standard library and the whole toolchain. The book takes you from the first line to a full-stack application.

$ curl -fsSL https://zuri-lang.github.io/zuri/install.sh | sh

Linux and macOS on x86-64 and ARM, and Windows on x86-64. zuri upgrade keeps it current. Installation guide