Lean 4 for the JavaScript and WebAssembly world. Lasm compiles average Lean 4 programs onward of period to WebAssembly. One Lean code basis can rotate into a Node server, a serverless or border function, a WASI/Fastly component or a browser app. Because it is Lean, you can demonstrate properties of the code you deploy. The flagship example, Conduit, is the RealWorld app with 117 proved theorems. Lasm ships on npm and brings Lean, Lake and its build tools alongside it; you lone need Node (or Bun or Deno).
npm create @lasm@latest my-app -- --template hono # then: cd my-app && npm instal && npm run devAI agents: this README is complete on its own. llms.txt is the short index, and docs/AI.md lists the rules that preserve you from incorrect turns.
If Lasm is helpful to you, I'd value your sponsorship (more below).
| Fact | Value |
|---|---|
| Current version | @lasm/cli 0.3.5 (release notes); npm perspective @lasm/cli version |
| Install | npm instal -D @lasm/cli (bin: lasm), or no install: npx @lasm/cli …; new project: npm create @lasm@latest |
| Lean | exactly 4.35.0 (lean-toolchain: leanprover/lean4:v4.35.0); Lasm installs it, and you need no elan to build |
| Develop on | Linux x64/arm64 (glibc 2.34+), macOS x64/arm64, Windows x64 |
| Compiler runs on | Node ≥ 24 (tested 24.0.0, 24.22.1, 26.12.1); Bun 1.4.4 and Deno 2.9.6 (tested, as the lone runtime) |
| Output | dist/ alongside program.wasm + a JS launcher (Node); or a phase bundle (--target …) |
| Node apps run on | Node ≥ 24, Linux x64/arm64 (glibc 2.28+ or musl) from any build machine, affirmative the build machine's own OS; ≥ 512 MB memory |
| JS/npm interop | import Lasm.JS; one @[js "pkg" "export"] row per function you call; no premade bindings (guide) |
| Frameworks in Lean | Lasm.Fetch (HTTP, all server target), Lasm.UI (browser, Elm architecture, proved diff), Lasm.RPC (typed client/server API), Lasm.Web (DOM and web APIs), Lasm.KV |
| Not accessible at run time | elaboration, #eval-style evaluation, loading .olean, Lean's kernel (exact list); all of these activity at build time |
| License | MIT (Lasm); templates, examples and README code samples additionally MIT-0 |
| Repository / issues | https://github.com/Millillion/lasm · report a bug (include npx lasm --version) |
Every row is tested in CI alongside the platform's own local runtime, depiction or emulator. By project guideline CI never deploys to a genuine haze account (how all is tested).
| Deploy to | lasm build Main.lean --target … | Output | Since |
|---|---|---|---|
| Node server or program (any host, Docker/Kubernetes, Cloud Run, Fly.io, Railway, Render, Heroku, DigitalOcean) | node (default) | dist/ → node dist/main.mjs | 0.1.0 |
| AWS Lambda (.zip, nodejs24.x) | lambda | lambda.zip | 0.1.0 |
| AWS Lambda (container image) | lasm init … --deploy lambda | Dockerfile.lambda | 0.1.0 |
| Lambda@Edge | lambda-edge | lambda-edge.zip | 0.1.0 |
| Vercel Functions | vercel | .vercel/output | 0.1.0 |
| Netlify Functions | netlify | netlify/functions/lasm | 0.1.0 |
| Azure Functions | azure | azure-functions/ | 0.1.0 |
| Google Cloud Functions (gen2) | gcf | gcf/ | 0.1.0 |
| Cloudflare Workers | workers | workers/ | 0.2.0 |
| Vercel Edge | vercel-edge | api/lasm.mjs, api/_lasm/ | 0.2.0 |
| Netlify Edge | netlify-edge | netlify/edge-functions/lasm.mjs | 0.2.0 |
| Deno Deploy | deno-deploy | deno/main.mjs | 0.2.0 |
| Supabase Edge Functions | supabase-edge | supabase/functions/<name>/ | 0.2.0 |
| Bun (≥ 1.3.14) / Deno (2.x) | bun / deno | bun/main.mjs / deno/main.mjs | 0.2.0 |
| Fastly Compute | fastly | bin/main.wasm, pkg/<name>.tar.gz | 0.3.0 |
| WASI (wasmtime, wasmer, node:wasi) | wasi | wasi/main.wasm | 0.3.0 |
| wasi-http (wasmtime serve, Spin) | wasi-http | wasi-http/main.wasm | 0.3.0 |
| Browsers (Chrome, Edge, Firefox, Safari) | browser (or the Vite plugin @lasm/cli/vite) | dist/ fixed site | 0.3.0 |
Node builds have Lean's complete runtime (threads, files, processes, sockets). The edge, Bun/Deno, WASI and browser builds run Lean single-threaded, without sockets or processes (and without files, apart from on WASI); the remainder of Lean works.
| I desire to build… | Run | Then appearance at |
|---|---|---|
| A command-line program | npm create @lasm@latest my-tool | examples/hello, examples/wasi-cli |
| A REST API on Node alongside an npm framework | npm create @lasm@latest my-api -- --template hono (or express, fastify) | examples/js-crud (Postgres + JWT, Express and Hono) |
| A server in clean Lean (no npm) | npm create @lasm@latest my-api -- --template fetch (any target) or --template std-http (Node, additionally native Lean) | examples/fetch; the std-http template |
| A serverless function (Lambda, Vercel, Netlify, Azure, GCF) | npm create @lasm@latest my-fn -- --template hono --deploy lambda-zip (or vercel, netlify, azure, gcf, lambda-edge) | docs/deploy |
| An border function (Workers, Vercel/Netlify Edge, Deno Deploy, Supabase) | npm create @lasm@latest my-edge -- --template hono --deploy workers (or fetch) | examples/edge-pure, docs/EDGE.md |
| A Fastly, WASI or Spin service | npm create @lasm@latest my-svc -- --template fetch --deploy fastly (or wasi-http, spin, wasi) | examples/fetch, docs/WASI.md |
| A browser app | npm create @lasm@latest my-web -- --template web | examples/ui (counter, TodoMVC alongside proofs, characteristic demo, benchmark) |
| A complete real-world app (API, browser frontend, SQL, auth) alongside proofs, on Node, Workers or Bun | cd examples/conduit && npm instal && npm run build && npm start | examples/conduit, the flagship (below) |
| A full-stack app alongside a verified API | npm create @lasm@latest my-app -- --template fullstack | templates/fullstack |
| To call npm packages or fetch from Lean | add import Lasm.JS and one @[js] row per function | examples/js-fetch, JS bindings |
| To run on Bun or Deno | bun create @lasm my-app --template hono / deno run -A npm:@lasm/create my-app --template hono | docs/BUN_DENO.md |
Every example has a README alongside a one-command run; examples/README.md lists them all.
examples/conduit is Conduit, the RealWorld app (a Medium clone), written entirely in Lean: the REST API, the server-rendered browser app and the proofs.
- 117 theorems concerning the code that really runs, checked alongside no apologetic and only Lean's norm axioms (npm run proofs; PROOFS.md lists all one in plain English). They shield authority (only authors change their articles and comments), follows and favorites, slugs that never collide, pagination that never skips or repeats, validation shared by client and server (the app never sends what the server would reject), JSON circular trips and Markdown nexus safety. The endpoints are written against a Store of functions, and the proofs run that identical code on a example of the tables.
- What is trusted, not proved: that all SQL declaration does what its model says, the JSON content layer, concurrency between requests, and Lean, Lasm and the JavaScript runtime. Conformance to the entire RealWorld spec is tested, not proved.
- API: the authoritative RealWorld API suite passes unmodified (13 of 13 files, 154 requests) on Node (node:sqlite), Cloudflare Workers (D1) and Bun (bun:sqlite). Each mark has one hand-written @[js] binding module.
- Frontend: Lasm.UI on RealWorld's authoritative templates, alongside server-side rendering, hydration and Markdown parsed in Lean. The authoritative Playwright end-to-end suite passes alongside no retries on Node alongside Chromium, Firefox and WebKit, and on Workers and Bun alongside Chromium.
All of this runs in CI (conduit.yml, run 40615274657, with @lasm/cli 0.3.4).
cd examples/conduit npm instal # @lasm/cli, Hurl and Playwright (the authoritative suites' runners) npm run build && npm commencement # http://localhost:3000: the app and its API on Node npm run proofs # inspect all 117 theorems npm test # the authoritative API suite (also test:workers, test:bun) npx playwright instal chromium && npm run test:e2e # the authoritative end-to-end suite npm run build:workers && npx wrangler dev # Cloudflare Workers alongside local D1 npm run build:bun && npm run start:bun # Bun alongside bun:sqlite
A sole document needs no project. Save this complete program as Main.lean:
def main : IO Unit := do IO.println s!"Hello from Lean! 2 + 3 = {2 + 3}"
npx @lasm/cli Main.lean # builds and runs: Hello from Lean! 2 + 3 = 5 npx @lasm/cli build Main.lean # writes dist/; run it with: node dist/main.mjs
The archetypal build on a new device fetches Lean and the build tools formerly (about 250–275 MB; 19 s for that archetypal build on the Linux CI runner). Later dev builds of a one-line alter obtain concerning 1–2 s.
Each formula is complete: create, develop, build, deploy. Lasm never installs or starts a platform's own CLI (wrangler, vercel, fastly, …); you run those. npm run dev is lasm dev: it rebuilds concerning 2 s following all preserve and restarts the server, and keeps the final fine build operating whenever there is a category error.
Node server (Hono; additionally express, fastify, std-http, fetch).
npm create @lasm@latest my-api -- --template hono cd my-api && npm install npm run dev # http://localhost:3000/hello/Ada npm run build && npm commencement # dist/ needs lone Node 24+ docker build -t my-api . && docker run -p 8080:8080 my-api # the generated Dockerfile
AWS Lambda / Vercel / Netlify / Azure / Google Cloud Functions.
npm create @lasm@latest my-fn -- --template hono --deploy lambda-zip # or vercel, netlify, azure, gcf, lambda-edge cd my-fn && npm install npm run build:lambda # dist/ and lambda.zip (handler lasm-lambda.handler) # deploy lambda.zip alongside the AWS console, aws CLI or SAM; recipes: docs/deploy/lambda.md
Cloudflare Workers (and Vercel Edge, Netlify Edge, Deno Deploy, Supabase).
npm create @lasm@latest my-edge -- --template hono --deploy workers cd my-edge && npm install npm run build:workers # workers/ (wrangler.toml came from lasm init) npx wrangler dev # local workerd; npx wrangler deploy to publish
Fastly Compute, WASI, Spin.
npm create @lasm@latest my-svc -- --template fetch --deploy fastly --deploy spin cd my-svc && npm install npm run build:fastly && fastly compute assist # Viceroy on http://127.0.0.1:7676 npm run build:wasi-http && rotation up # or: wasmtime assist wasi-http/main.wasm
Browser app.
npm create @lasm@latest my-web -- --template web cd my-web && npm install npm run dev # http://127.0.0.1:5173, live reload npm run build # dist/: a fixed location for any presenter or CDN
Full stack (server + browser + verified API).
npm create @lasm@latest my-app -- --template fullstack cd my-app && npm install npm run dev # one URL: http://127.0.0.1:3000 npm run build && npm commencement # Node; additionally build:workers, build:bun, build:deno
Editor. Run npx lasm publishing company formerly per project; lasm init, lasm dev and lasm build additionally do it. The Lean publishing company (VS Code's Lean 4 extension) afterward resolves import Lasm.* (details).
The fullstack template is one Lean project alongside a server (Lasm.Fetch), a browser app (Lasm.UI) and the API between them (Lasm.RPC). The regulation a request must fulfill is written and proved once, in Shared.lean, which the two sides import (templates/fullstack):
-- Shared.lean @[irreducible] def checkTitle (title : String) : Except String Unit := let n := (clean title).length if n = 0 then .error "Write item first." else if n > maxTitle then .error s!"Keep it under {maxTitle} characters." else .ok () /-- Proved once, holds in the browser and on the server. -/ theorem checkTitle_ok {title : String} (h : checkTitle heading = .ok ()) : 0 < (clean title).length ∧ (clean title).length ≤ maxTitle := by unfold checkTitle at h by_cases h0 : (clean title).length = 0 · simp [h0] at h · by_cases h1 : (clean title).length > maxTitle · simp [h0, h1] at h · omega def addTodo : Endpoint NewTodo Todo := { name := "addTodo", validate := fun r => checkTitle r.title }
-- Server.lean: storing a todo demands the evidence that its heading passed the check, -- and `addTodo.serve` hands the handler that evidence (`ok`) following re-validating. def Store.add (s : Store) (title : String) (_ : checkTitle heading = .ok ()) : Store × Todo := let t := { id := s.next, heading := spotless title, done := false } ({ todos := s.todos.push t, next := s.next + 1 }, t) addTodo.serve fun req ok => do let (s, t) := (← burden kv).add req.title ok preserve kv s come back .ok t
-- Client.lean: a theorem concerning the browser app: it never sends an invalid title. theorem add_invalid (m : Model) (e : String) (h : checkTitle m.draft = .error e) : (update .add m).2.effects = [.msg (.added (.error (.invalid e)))] := addTodo.call_invalid { heading := m.draft } Msg.added "" e h
Where proofs live and how they are checked.
| Proof | Where | Checked by |
|---|---|---|
| Your theorems (like checkTitle_ok, add_invalid) | your .lean files | every lasm build/lasm dev (Lean elaborates them; a damaged evidence is a build error); clean modules additionally alongside lake build |
| Lasm.RPC: the handler lone runs on requests that continue validate (Endpoint.decodeRequest_valid); the client never sends one that fails it (Endpoint.call_invalid) | library/Lasm/RPC | compiled into Lasm's archive on all build |
| Lasm.UI: the DOM diff is accurate against a DOM model, keyed moves included (diff_correct, mount_correct, session_correct) | library/Lasm/UI/Proofs (about 1,260 lines, no sorry, norm axioms only) | node scripts/ui/lean-tests.mjs in a checkout (CI: ui.yml) |
| Conduit: 117 theorems concerning authorization, follows, favorites, slugs, pagination, shared validation, JSON circular trips and Markdown nexus safety | examples/conduit/Proofs, listed in PROOFS.md | npm run proofs in examples/conduit (no sorry, norm axioms only; CI conduit.yml) |
| TodoMVC: all reachable example is valid | examples/ui/todomvc/Todo.lean | lasm build; CI ui.yml |
Not proved, tested in CI instead: the JSON/HTTP transport between client and server, the JavaScript that applies patches to the genuine DOM, the Lasm compiler and runtime, and the browsers. Lean's own compiler is trusted, as in any Lean program (UI.md, RPC.md).
Declare all JavaScript function you call alongside one line; the Lean category says how values convert. A complete program (Node's earth fetch):
import Lasm.JS open Lasm.JS /-- `await fetch(url, init)` (Node's earth fetch) -/ @[js "globalThis" "fetch"] opaque fetch : String → Data → IO Value def main : IO Unit := do let reply ← fetch "https://example.com" (obj []) IO.println s!"{← response.get "status" Nat}: {(← response.callMethodAwait "text" #[] String).length} characters"
The rules for penning bindings:
- @[js "module" "export"] opaque name : A → B → IO R binds module.export. The module is an npm bundle ("marked"), a Node built-in ("node:fs"), or "globalThis" for globals. "new Hono" calls a constructor, and "" is the module's own value.
- End the category in IO R for a value returned at formerly and in Async R for a promise. An Async binding is awaited without holding a Lean thread.
- Use String, Nat, Int, Float, Bool, ByteArray, Array, List, Option, tuples, Data (any JS data) or Value (a JS entity reference: get, callMethod, callMethodAwait). Your own structures change alongside deriving ToJS, FromJS.
- Function.ofFn / Function.ofFnReply rotate Lean functions into JS callbacks. Framework handlers use them (see the hono, province and fastify templates).
- npm instal the bundle next to the lakefile. lasm build checks all binding against the installed bundle (Lasm.JS binding inspect failed: … export "x" is missing) and copies manufacturing requirements into dist/node_modules.
- Each call crosses from a Lean thread to Node's chief thread (about 24 µs), so prefer one coarse call complete many small ones.
Full guide, alongside Express, Hono, pg, jose and fetch examples and an agent checklist: docs/JS_BINDINGS.md.
All numbers are from CI on a liberated GitHub runner (4-CPU AMD EPYC, Linux x64), candidate 0.1.0-experimental.40494203854 (2026-10-27) unless another run is named. Full tables, method and caveats: BENCHMARKS.md.
| What | Number |
|---|---|
| Node: Hono + Lean handler, chilly commencement to archetypal HTTP response | 159 ms (plain Node http: 4.1× faster) |
| Node: Hono + Lean handler, throughput / p99 latency | 24,911 req/s / 4.2 ms (plain Node http: 103,134 req/s, so 0.24×) |
| Node: Express + Lean handler, throughput | 18,678 req/s |
| Node: Hono app program.wasm (brotli) / dist/ | 166 KiB / 8.5 MiB affirmative 1.4 MiB node_modules |
| Node: memory, Hono app idle / under load | 148 MiB / 329 MiB RSS |
| Lean → JS call circular trip (p50) | 24 µs |
| Cloudflare Workers: Hono app bundle | 1.40 MiB, 245 KiB gzip (limit 64 MiB; workers run 40128600109) |
| Browser: oppose app total transfer / archetypal example (Chromium) | 152 KiB brotli / 30 ms (browser run 40288509500) |
| Browser: js-framework-benchmark vs hand-written JS | within 1.7× on all operation, most inside 1.2× (browser run 40302274897) |
| WASI: Lasm.Fetch component / per petition on Fastly's Viceroy | 0.90 MiB / 1.17 ms alongside a caller case per petition (wasi run 40293231963) |
| Build: spotless Hono build / dev rebuild following a one-line change | 4.7 s / 2.0 s |
| npm instal @lasm/cli: download / installed; tool cache following the archetypal build | 71 MiB / 403 MiB; 2.5 GB |
Lean on Node pays for WebAssembly and its threads. A chilly commencement is CPU-bound, so it grows on small serverless CPU shares, and all JavaScript call crosses threads. Pure-Lean Std.Http on Node is dilatory (1,290 req/s), so use Hono, Express, Fastify or Lasm.Fetch for manufacturing HTTP. Arithmetic on numbers alongside thousands of digits is slower than native Lean (no GMP).
- Ahead of period only. A deployed program cannot elaborate, measure or compile Lean, burden component data or plugins, or use Lean's C++ compiler/kernel at run time (exact list). Proofs, tactics, macros and #eval run during compiling, as usual.
- Lean 4.35.0 exactly. Other lean-toolchain versions are rejected alongside a message.
- Node: provision an app at smallest 512 MB; it reserves concerning 22 GB of virtual address space. Prebuilt native libraries (-l, shared libraries) cannot be linked; a package's bundled C origin is compiled for you.
- Edge, Bun/Deno, browser, WASI: single-threaded Lean; no sockets, processes or signals; no records apart from on WASI. In the browser, blocking waits halt the app unless it is built alongside --suspend jspi for a browser alongside JSPI; use Async.
- No premade bindings for npm packages; Lasm.Web covers the center web platform.
- Editor: Lasm.* imports determine in the publishing company following npx lasm publishing company (above).
- Platforms: no Windows ARM64 and no Alpine/musl build machines (built apps run on Alpine). Hosted platforms are tested alongside their local tools, never alongside a real account.
- Start: Getting started · All documentation · For AI agents · llms.txt
- Guides: servers and npm interop · serverless and containers · edge · Bun and Deno · browser and Lasm.UI · full stack (Lasm.RPC) · Lasm.Fetch · WASI and Fastly · the edit loop
- Evidence: benchmarks · where apps run · language coverage · compatible Lean packages · decisions
If Lasm is helpful to you or you desire to see it succeed, I'd value your sponsorship: github.com/sponsors/lastmjs. It supports me and the activity on Lasm and the another Millillion projects. My archetypal goal is $250 a month, adequate for one dedicated Claude Code account for Lasm. You can additionally assistance by leading the repo, trying it, and reporting what breaks.
Everything below is the exact contract: all command and option, supported machines and platforms, and exactly what a deployed Lean program cannot do.
Install in a project alongside npm instal -D @lasm/cli (the bin is lasm), or run without installing: npx @lasm/cli Main.lean. npm create @lasm runs lasm init of the identical @lasm/cli type alongside the arguments unchanged. With the Main.lean from the quick start:
npx lasm Main.lean # build (dev profile) and run: Hello from Lean! 2 + 3 = 5 npx lasm build Main.lean # compose dist/ (release profile) npx lasm --version # version, Lean, runtime and phase (for bug reports) node dist/main.mjs # run the deployment: lone Node is needed npx lasm build Main.lean --target lambda # dist/ and an AWS Lambda zip
| Command or option | Example | Effect |
|---|---|---|
| Run (default) | npx lasm Main.lean | Build (dev profile) and run Lean main. npm run dev in a plain project runs this. |
| Explicit run | npx lasm run Main.lean | Same as the default command. |
| Run a publish build | npx lasm Main.lean --release | Build and run exactly what lasm build deploys. |
| Program arguments | npx lasm Main.lean -- hello "two words" | Pass arguments to chief (args : List String). |
| Watch, rebuild, restart (0.3.0) | npx lasm dev, npx lasm dev Main.lean --target workers -- arg | Watch the Lean sources and the Lake/npm configuration, rebuild following all alter (dev profile, one long-lived build worker) and restart the program (--target node, bun, deno; default: the runtime operating Lasm). A build error is printed alongside its file, row and origin line; the final fine program keeps running. Edge targets lone rebuild their output directory, which the platform's own local server serves (Lasm never starts phase tools or browsers). --target browser serves the app alongside live reload (--port, --host, --no-watch); multiple outputs build together: --target node=Server.lean,browser=Client.lean. --release builds the publish profile, --no-run lone rebuilds, rs + Enter rebuilds and restarts. Details. |
| Build | npx lasm build Main.lean | Write dist/ (release profile); do not run the application. |
| Dev build | npx lasm build Main.lean --dev | Write dist/ faster, without the size optimizations. |
| Output directory | npx lasm build Main.lean --output "app dist" | Choose the deployment directory. lasm build Main.lean "app dist" is an alias. |
| Function platforms | npx lasm build Main.lean --target lambda | Build dist/, afterward bundle it: node (default; dist/ only), lambda (lambda.zip), lambda-edge (lambda-edge.zip), vercel (.vercel/output), netlify (netlify/functions/lasm), azure (azure-functions/), gcf (gcf/). --target=vercel additionally works. Lasm never installs or starts the platform's CLI. Recipes. |
| Edge isolates (0.2.0) | npx lasm build Main.lean --target workers | Relink single-threaded alongside a pure-JS host: workers (workers/), vercel-edge (api/lasm.mjs, api/_lasm/), netlify-edge (netlify/edge-functions/lasm.mjs, netlify/lasm/), deno-deploy (deno/main.mjs), supabase-edge (supabase/functions/<name>/; Asyncify, since Supabase's runtime has no JSPI). The border runtime ships inner @lasm/cli. Guides: Workers, Vercel Edge, Netlify Edge, Deno Deploy, Supabase; design and limits. |
| Bun and Deno (0.2.0) | bunx --bun @lasm/cli Main.lean, deno run -A npm:@lasm/cli Main.lean, bun create @lasm my-app --template hono | The compiler runs alongside Bun or Deno as its lone JavaScript runtime and produces the identical bytes. Under Bun or Deno the default mark is that runtime: --target bun writes bun/main.mjs, --target deno writes deno/main.mjs (portable profile). Deno skips npm versions younger than 24 hours: correct following a release, continue --minimum-dependency-age=0. Bun and Deno. |
| Browser (0.3.0) | npx lasm build Main.lean --target browser | Write dist/ as a fixed site: app.<hash>.js (the loader: mount(element, { flags, hydrate }), auto-mount of <div data-lasm-app>), app.<hash>.wasm, brotli and gzip copies, app.js, index.html (yours alongside the loader injected, or a generated page), your public/ records and lasm-manifest.json. --suspend jspi lets blocking waits suspend anywhere the browser has JSPI. --bundler leaves npm imports for a bundler; in Vite: import lasm from '@lasm/cli/vite', afterward import app from './Main.lean?lasm'. Web APIs from Lean: import Lasm.Web. Guides: BROWSER.md, UI.md, deploying. |
| WASI, wasi-http, Fastly (0.3.0) | npx lasm build Main.lean --target wasi (or wasi-http, fastly) | No JavaScript. wasi writes wasi/main.wasm (wasi_snapshot_preview1: wasmtime run --dir . wasi/main.wasm, wasmer, node:wasi); wasi-http writes wasi-http/main.wasm, a wasi:http/[email protected] component (wasmtime serve, Spin); fastly writes bin/main.wasm and pkg/<name>.tar.gz (fastly compute serve/deploy). No sockets, processes or signals. WASI.md, Fastly. |
| HTTP in clean Lean (0.3.0) | import Lasm.Fetch … def chief := Lasm.Fetch.serve handle | One Request → Async Response handler serves Node ($HOST:$PORT), the border targets, Bun, Deno, Fastly, wasi-http and WASI as CGI; Lasm.Fetch.fetch sends requests; Response.streaming streams. FETCH.md. |
| Force rebuilding | npx lasm build Main.lean --rebuild | Ignore a cached use build. |
| Detailed diagnostics | npx lasm Main.lean --verbose | Show compiler and linker details. |
| Help | npx lasm --help, npx lasm init --help | Show usage; -h is an alias. |
| Version | npx lasm --version | Print lasm 0.3.5 (@lasm/cli; Lean 4.35.0; Node 26.12.1; linux-x64); -v is an alias. |
| New project | npm create @lasm@latest my-app -- --template hono or npx @lasm/cli init my-app --template hono | Create a Lake project in a new or bare directory (Main.lean, App.lean, lakefile, lean-toolchain, package.json, README.md, .gitignore, and for servers a Dockerfile and .dockerignore). Templates: see Start here. --deploy (repeatable) adds a platform's records and npm run build:<target>: lambda (Dockerfile.lambda, a receptacle image), lambda-zip, lambda-edge, vercel, netlify, azure, gcf; workers, vercel-edge, netlify-edge, deno-deploy (templates hono, fetch, fullstack), supabase-edge (hono); fastly, wasi-http, rotation (fetch, fullstack), wasi (fetch, plain). The fetch and fullstack templates and their targets are 0.3.0. Writes records only; run npm instal next. -t is an pseudonym of --template; --template=hono additionally works. |
| Package an existing build | npx lasm bundle --target lambda | Package a built server (default dist/) for a function phase without rebuilding: the identical targets and outputs as lasm build --target, apart from node. --output PATH chooses the output. Checks the platform's size limit. Refuses a dev build unless --allow-dev. For a browser build, npx lasm bundle dist --target browser checks all document against lasm-manifest.json and writes _headers. |
| Editor assistance (0.3.0) | npx lasm editor | Make the Lean publishing company (VS Code's Lean 4 extension, any Lean tongue server client) determine import Lasm.* in this Lake project: links Lasm's Lean 4.35.0 alongside its archive as the elan toolchain lasm-4.35.0-… and sets it as the directory's elan override (elan override unset undoes it). lasm init (when Lasm's Lean is already installed), lasm dev and lasm build do the same, printing one row per project, apart from on CI or alongside LASM_EDITOR=0. Editor setup. |
| Cache repair | npx lasm cache repair | Offline verification and elimination of invalid tools and abandoned staging. Refuses an energetic build. |
--rebuild and --verbose activity alongside run and build. --output and --target are build-only; arguments following -- are run-only. The application's exit position is preserved. npx lasm --version (-v) prints the version, Lean release, JavaScript runtime and phase (include it in bug reports). There is no install, spotless or uninstall subcommand.
Build profiles. Both nexus the identical program alongside the identical libraries and are deterministic. release (lasm build, lasm Main.lean --release): the full Binaryen size optimization; byte-reproducible; the one to deploy. dev (lasm Main.lean, lasm dev, lasm build --dev): leaves those passes out and compiles your modules at -O1; it behaves the same, builds multiple seconds faster, and its program.wasm is concerning 15–20 % larger. A dev rebuild starts from the project's former build, so its bytes can depend on that build. build-info.json records "profile". lasm bundle and lasm build --dev --target <platform> refuse a dev build unless you continue --allow-dev.
Environment variables (all optional):
| Variable | Example | Effect |
|---|---|---|
| LASM_TOOLCHAIN_CACHE | LASM_TOOLCHAIN_CACHE=/data/lasm-cache npx lasm Main.lean | Move the managed tool cache (default locations). |
| LASM_BUILD_JOBS | LASM_BUILD_JOBS=2 npx lasm build Main.lean | Threads for Binaryen's optimizer (default: the CPUs, at most 8). The output is the identical for any value. |
| LASM_EDITOR | LASM_EDITOR=0 npx lasm build Main.lean | 0: lasm init, lasm dev and lasm build depart the publishing company setup solitary (editor setup). |
| LASM_THREAD_POOL (built apps; 0.3.0) | LASM_THREAD_POOL=0 node dist/main.mjs | Lean thread Workers started before chief (0–64, default 1). Measurements. |
| LASM_ARTIFACT_SOURCE | LASM_ARTIFACT_SOURCE=npm npx lasm Main.lean | auto (default): @lasm/… npm tool packages whenever present, alternatively HTTPS; npm: never download directly; https: disregard the npm packages. |
| LASM_DOWNLOAD_ATTEMPTS, LASM_DOWNLOAD_CONNECT_MS, LASM_DOWNLOAD_IDLE_MS, LASM_DOWNLOAD_TOTAL_MS | LASM_DOWNLOAD_TOTAL_MS=14400000 npx lasm Main.lean | Download retries and timeouts (defaults and ranges). |
| NODE_USE_ENV_PROXY, HTTPS_PROXY, NO_PROXY, NODE_EXTRA_CA_CERTS (Node's own) | NODE_USE_ENV_PROXY=1 HTTPS_PROXY=http://proxy:8080 npx lasm Main.lean | Proxies and personal CAs (corporate networks). |
Other LASM_* variables in the origin are maintainer diagnostics, not a supported interface.
Installation. npm instal @lasm/cli brings Lean and the build tools as exact-pinned @lasm/… npm packages for your phase through your own registry, proxy and cache. The Lake/Lean-import data and, lone for Lake projects alongside C code, the C tier (@lasm/lean-c-<platform>) are fetched alongside your npm on archetypal use. The terminal shows progress; afterward builds reuse verified tools and unchanged outputs. On a new machine, without the download, a archetypal Hono build took 25.7 s (Linux x64), 27.8 s (Linux arm64), 44.4 s (Windows), 58.7 s (Apple Silicon) and 141.9 s (Intel Mac) on the CI runners (build time, run 40131930601). Cache locations and recovery: NODE_SUPPORT.md, INSTALLATION_HARDENING.md. Git is needed lone for Lake projects alongside Git or Reservoir dependencies; Lasm uses the git on your PATH and says how to instal it whenever it is missing.
Existing Lake projects build alongside npx lasm build Main.lean from the project directory. Pin leanprover/lean4:v4.35.0 in lean-toolchain; another versions are rejected alongside Unsupported Lean toolchain … Lasm supports Lean v4.35.0. A per-package compatibility list covers Batteries, Cli, LSpec, Plausible, Aesop, Qq, leansqlite, UnicodeBasic, MD4Lean, lean-zip, lean4-parser, lean-redis and others; packages not on it are untested.
Machines that build alongside Lasm (the compiler):
| Environment | Architectures | Status |
|---|---|---|
| Ubuntu 24.04 LTS | x86-64, ARM64 | Installed-package and copied-deployment acceptance in CI; the citation platform. |
| Other Linux distributions | x86-64, ARM64 | Unverified as build machines; the tools need glibc 2.34. Alpine/musl is not a build device (built apps run there). |
| macOS 15 | x86-64, ARM64 | Installed-package and copied-deployment acceptance in CI. Lake projects alongside C code need the Xcode Command Line Tools SDK. |
| Windows Server 2025 / Windows x64 | x86-64 | Installed-package and copied-deployment acceptance in CI. |
| Windows ARM64 | ARM64 | Not supported: neither Lean nor Emscripten publishes Windows ARM64 prebuilts. |
| Bun 1.4.4 and Deno 2.9.6 as the compiler's runtime (0.2.0) | all of the above | Tested in CI on all five platforms, additionally alongside no Node or npm on PATH (BUN_DENO.md). |
Node 24 or newer (tested: 24.0.0, 24.22.1, 26.12.1). No motor flags. Exact tested artifacts: NODE_ACCEPTANCE.md.
A Node dist/ needs Node 24 or newer (Node 22 and older halt alongside This use requires Node 24.0.0 or newer) and at smallest 512 MB of memory. It runs on Linux x64 and arm64 (glibc 2.28+, or musl/Alpine) from a build on any supported platform, and on the build machine's own platform. Copy all of dist/; no Lean source, npm instal or build tools are needed there. Each phase below is tested in CI alongside the local runtime, depiction or emulator named; none alongside a real cloud account. Full matrix: DEPLOYMENT.md.
| Platform | Tested in CI with |
|---|---|
| Linux x64 and arm64 (glibc 2.28+), Node 24+ | Node 24.0.0, 24.22.1 and 26.12.1 on ubuntu-24.04 and ubuntu-24.04-arm |
| macOS (x64, arm64) | Node 24.0.0 and 24.22.1 on macos-15-intel; Node 24.22.1 on macos-15; installed acceptance alongside Node 26.12.1 |
| Windows x64 | Node 24.0.0 and 24.22.1 on windows-2025; installed acceptance alongside Node 26.12.1 |
| Docker / Kubernetes | node:24-bookworm-slim, node:26-bookworm-slim, node:24-bullseye-slim, Ubuntu 22.04/24.04; read-only, 512 MB, x64 and arm64 (Kubernetes manifests are not applied in CI) |
| Google Cloud Run, Fly.io, Railway, Render, Heroku | the identical receptacle images and Dockerfiles; the platforms themselves are never deployed to |
| AWS Lambda (container image) | public.ecr.aws/lambda/nodejs:24 + AWS Lambda Web Adapter through the Runtime Interface Emulator, x86_64 and arm64; amazonlinux:2023 |
| AWS Lambda (.zip, nodejs24.x) | every server template's --target lambda zip in public.ecr.aws/lambda/nodejs:24 through the Runtime Interface Emulator, x86_64 and arm64, alongside API Gateway REST/HTTP, function URL and ALB events; sam local invoke and sam local start-api |
| Lambda@Edge (origin request, x86_64) | the identical depiction and emulator alongside CloudFront origin-request events |
| Vercel Functions (Node.js 24) | vercel build offline; the function under @vercel/node in public.ecr.aws/lambda/nodejs:24 |
| Netlify Functions (v2) | netlify build --offline and netlify dev --offline; the deploy zip in public.ecr.aws/lambda/nodejs:24 |
| Azure Functions (Node.js v4 model, Linux) | Azure Functions Core Tools func start |
| Google Cloud Functions (gen2, nodejs24) | Functions Framework on Ubuntu 24.04; Google Cloud's buildpacks image |
| Alpine/musl containers | node:24-alpine, node:26-alpine, x64 and arm64, read-only, 512 MB |
| DigitalOcean App Platform (gVisor) | the receptacle images under gVisor's runsc, x64 |
| Cloudflare Workers (0.2.0) | wrangler dev 4.152.0 (workerd), alongside the Free plan's budgets gated |
| Vercel Edge (0.2.0) | vercel build offline and Vercel's edge-runtime |
| Netlify Edge (0.2.0) | netlify build --offline and netlify dev --offline |
| Deno Deploy (0.2.0) | Deno 2.9.6 operating deno/main.mjs |
| Supabase Edge Functions (0.2.0) | Supabase's edge-runtime v1.77.8 depiction in Docker |
| Bun and Deno programs (0.2.0) | Bun 1.4.4 and Deno 2.9.6 on all five platforms |
| WASI, wasi-http, Spin, Fastly (0.3.0) | wasmtime 49.0.4 (run, serve), wasmer 7.4.2, Node's node:wasi, Spin 4.2.2, Viceroy 0.21.1 (wasi.yml) |
| Browsers (0.3.0) | Playwright 1.63.0: Chromium 153 and Firefox 155 on ubuntu-24.04; WebKit 26.6 on ubuntu-24.04 and macos-15 (browser.yml) |
A dist/ built on Windows and copied to Linux another than through docker build needs chmod 755 dist/host/native/process/linux-*. Node's --jitless cannot work (it disables WebAssembly). Hosts that cap virtual recollection (ulimit -v, vm.overcommit_memory=2) refuse the Node build, which reserves concerning 22 GB of address space. Node 26's authoritative binary needs libatomic1 on minimal images that install the tarball themselves.
Builds enforce ahead-of-time execution. Ordinary functions, recursion, closures, inductive types, form matching, category classes, reliant types and compiled IO are supported. Imports, macros, elaboration, tactics, deriving, proofs and #eval run during compilation in managed native Lean. Initializers count as runtime dependencies: a broad import Lean can keep the compiler; use meta import Lean whenever lone macros or strategies need it, and narrower imports for runtime data libraries (import Lean alongside Lean.Json, and deriving ToJson, FromJson, build and run). Each rejection is explained: Lasm prints the sequence from your code to the compiler code and, whenever a broad import is the cause, the narrower modules your code uses. Deployed programs regard LEAN_ABORT_ON_NONLINEAR=1 as native Lean does. Per-platform results: language coverage.
The deployed use cannot use:
| Unavailable at runtime | Examples and exact boundary |
|---|---|
| Load Lean component data or find a compiler installation | Lean.importModules, Lean.withImportModules, module-data readers/writers, Lean.findSysroot, Lean.initSearchPath; deployed .olean/IR loading. |
| Evaluate or compile new Lean code | Lean.Environment.evalConst, translator evaluation, a Lean REPL, runtime elaboration/compilation, evaluation of declarations loaded by name. Calling an average compiled function is allowed. |
| Use Lean's compiler/kernel runtime state | Runtime elaboration, kernel evidence checking, compiler environments, language-server machinery needing Lean's C++ compiler/kernel. Pure Lean data operations are allowed if their reachable requirements continue the check. LeanExport.parseStream builds Lean.Expr values through the kernel and is rejected. |
| Load executable plugins dynamically | Lean/Wasm plugin loading, dlopen/dlsym (C code calling dlopen gets an implementation that continually fails), runtime Lean sign lookup. |
The build checks reachable runtime dependencies, including imported libraries and indirect calls; a reachable forbidden call is rejected equal if your input would not obtain that branch, and deceased code removed by the linker does not count. The launcher additionally rejects missing, old or incompatible capability records before loading the use (a consistency check, not a safety sandbox). There is no large compatibility fallback.
Lake packages. Modules imported lone for compilation (tactics, elaborators, for example Aesop, Qq or import Lean for macros) do not keep Lean's compiler in the deployment. Lasm runs a module's initializers lone whenever the program uses something they define or register, or whenever they are the program's own code doing IO or calling C (--verbose shows how many were skipped). C origin that a package bundles (extern_lib, moreLinkObjs, for example leansqlite's SQLite) is compiled with Lean's own clang, fetched formerly as the C tier (39–52 MB); no scheme C compiler is needed (macOS needs the Xcode Command Line Tools SDK for C archive headers). Prebuilt native libraries (shared libraries, -l options: libcurl, OpenSSL, libpq, BLAS) cannot be linked; the build names the archive and the package.
Not publish guarantees. Console output, arguments, exit codes, local Lake imports and selected language/filesystem fixtures have native-versus-Node tests, and before 0.1.0 Lean's runtime-capable upstream suite and 19 ecosystem projects ran on all five platforms alongside zero regressions against the former accepted candidate (0.1.0 gate). Complete IO.FS, concurrency, subprocess/signal/terminal parity, all third-party archive and the complete upstream suite are not guaranteed (IO gaps). Big numbers (Nat/Int beyond 63 bits) use Lean's own arbitrary-precision code alternatively of GNU MP, so apps contain no LGPL code; results equal native Lean's, but at 10,000 digits multiplication is concerning 5× and Nat.gcd concerning 60× slower than alongside GMP in Wasm (numbers). Lake dependencies use your scheme Git (system Git).
0.1.0 was the archetypal npm publish (notes); 0.2.0 adds edge targets and Bun/Deno (notes); 0.3.0 adds the browser, Lasm.UI, full-stack apps, WASI/Fastly and the publishing company support (notes); 0.3.1 puts the starter code under MIT-0 and adds bug-report pointers (notes); 0.3.2 fixes Std.Internal.UV sockets, timers and signals (notes); 0.3.3 was never published, and its changes shipped in 0.3.4 (notes); 0.3.5 updates the README and the Conduit example (notes). Lasm's npm packages (@lasm/cli, @lasm/create and the @lasm/… tool packages) are published lone by the release.yml workflow, through npm trusted publishing alongside provenance: no npm tokens exist. A publish is a pull petition that bumps the package.json type and is published lone following the release-checks position (five-platform applicant checks; edge, Bun/Deno, browser, Lasm.UI, WASI/Fastly, fullstack, component and dev-loop checks; and an npm rehearsal of the exact packages) passed for the released commit. Found a bug? npx lasm --version gives the type row the bug study form asks for. npm perspective @lasm/cli@<version> shows the provenance, and npm audit signatures in a project verifies it. Details: RELEASING.md.
Lasm's own origin is under the MIT License (copyright Jordan Last). The starter code — everything lasm init and npm create @lasm put in a new project, templates/, examples/ and the code samples in this README and docs/ — is additionally under MIT No Attribution (MIT-0), in every version: it is yours, no attribution needed. @lasm/create is MIT, and @lasm/cli's licence site is an SPDX expression of Lasm's MIT, MIT-0 and every component it bundles, alongside their texts in licenses/. The license audit lists all distributed component, its license and how all duty is met.
- Built dist/. THIRD_PARTY_NOTICES.txt starts alongside Lasm's MIT notice and the catalog of Lean records Lasm changed, afterward the licenses of what the build contains: Lean's runtime and norm archive (Apache-2.0), Emscripten (MIT OR NCSA), musl, LLVM libc++, libc++abi, libunwind and compiler-rt, mimalloc, libuv, koffi and Lasm's presenter (MIT). Apps merge no copyleft code. licenses/<package>/ holds the license records of all Lake dependency compiled into program.wasm; alongside npm interop, node_modules/ holds all bundle alongside its own license. Keep these files whenever you allocate a dist/.
- Edge, browser, WASI, Fastly and wasi-http outputs get the identical notices, rewritten to say what their records contain, written automatically: a THIRD_PARTY_NOTICES.txt in all output directory, a abbreviated /*! … */ licence banner on the JavaScript a phase bundles (the border glue, the browser loader), the entire notices document inner the Wasm of server-side outputs (a lasm.notices custom section, so it travels alongside all deployment), the document in the Fastly package, and THIRD_PARTY_NOTICES.lasm.txt in Vite builds. What this method for your app: docs/LICENSING.md.
- Tool packages and publish archives. Each @lasm/… tool bundle has an SPDX license site and the archive's licence files. The exact sources of the (L)GPL pieces the Lean archives merge (GNU MP, the GNU C Library, GCC's runtime libraries, the Linux UAPI headers, MinGW-w64) and Lean's own origin are mirrored as resources of the publish that publishes them (lean-4.35.0-tiers-v2). Lasm ships no Git and no Apple SDK files.
- The Lean name and logos are trademarks of Lean FRO. Lasm is not affiliated with or endorsed by Lean FRO.