Nupp

LuaJIT with static guarantees.

Nupp adds checked types, resource contracts, concurrency, native compilation, and a complete project toolchain while keeping ordinary Lua modules and control flow.

A nuppeppo in a moonlit forest


local record Point
    x: number
    y: number
end

local function scale(point: Point, factor: number): Point
    return new Point(x = point.x * factor, y = point.y * factor)
end

Checked Lua

.lua, .g.nupp, and .nupp provide plain, gradual, and strict source boundaries. Records, structs, interfaces, unions, refinements, generics, and narrowing add contracts where a module needs them.

Compiler diagnostics carry stable codes, source spans, related locations, repair help, and structured fixes. See the language tour and type system.

local function consume(borrows file: LuaFile): string
    return file:read("*a")
end

do
    local report = assert(io.open("report.txt", "r"))
    print(consume(report))
end

Resources and foreign code

Affine ownership records a cleanup obligation in the type. Borrowing, pinning, and exact scopes make C pointer lifetimes and deterministic cleanup visible to the checker.

C headers import as checked declarations, and component builds embed checked modules in a C-owned process. See ownership, C interop, and embedding.

local tasks = nupp.tasks
local time = nupp.time

local function waitFor(results: {number}, index: integer, milliseconds: number): nil
    time.sleep(milliseconds)
    results[index] = milliseconds
end

local results: {number} = {}
with scope = tasks.open() do
    scope:spawn(results, 1, 20, waitFor)
    scope:spawn(results, 2, 10, waitFor)
end

print(results[1], results[2])

Waiting and parallel work

Suspension-aware functions keep ordinary call syntax and return types. A call blocks without a scheduler and parks its coroutine under a host handler. Structured task scopes and worker pools compose concurrent work at different isolation boundaries.

See suspension, task scopes, and workers.

local comptime function Optional(T: type): type
    return nupp.types.optional(T)
end

local value: Optional(string) = "ready"

Comptime and data

Comptime functions inspect and construct types, and comptime do evaluates ordinary Nupp during compilation. Reflection and derives turn those facts into checked serializers, layouts, and generated declarations.

The standard library includes files, networking, TLS, HTTP, processes, JSON, hashes, parsing, memory spans, and GPU storage. See comptime, serde, and the standard library.

local span = require("nupp.mem.span")

@aot
local function double(exclusive values: span.WriteSpan<float>): nil
    for index = 1, #values do
        values[index] = values[index] * 2.0
    end
end

CPU, SIMD, and GPU compilation

@aot lowers admitted CPU functions through verified IR to C or Wasm. Complete span maps can become lane-parallel, while target = "gpu" produces typed resident-buffer kernels and native or WebGPU artifacts.

See ahead-of-time compilation, vectorization, and GPU compute.

nupp.lua
portable = {
   kind = "modules",
   entries = {"main"},
   dialect = "lua51",
   outDir = "build/lua51",
}

Portable targets and packaging

A build target can lower for native LuaJIT or the portable Lua 5.1 surface. Projects can produce module trees, bundles, standalone binaries, embedded components, Wasm side modules, and browser packages.

See project builds, portable libraries, and Wasm applications.

nupp check                 # check the configured source graph
nupp fmt --write           # format project source
nupp test                  # build and run project tests
nupp build                 # build the default deliverable
nupp explain NUPP2119      # expand one diagnostic
nupp reference --for CODE  # print the relevant language section

Language-aware tools

The checker, builder, test runner, formatter, language server, documentation generator, profiler, coverage tool, migration tools, and compiler inspectors ship in one executable.

See tooling for the guided map and CLI reference for exact command options.