npx
A general-purpose language where data flows left to right, like a shell pipe. Failures are values you handle on the same line, and & runs work in the background.
Press Run, or ctrl+enter.
use ./name. Blocks are made by indentation.Your code stays in this page; nothing is sent anywhere unless the program asks the network.tour
Six ideas make up npx. Each one has a short example; "Load it" puts it in the playground above.
Pipes come first
a | f x means f x a: the value on the left goes in as the last argument. Every built-in puts its data last, so pipelines read top to bottom.
.name on its own is a function that reads that field.
orders | keep (fn o -> o.paid) | sort_by .total | map .total | sum | print
No brackets to call
Write greet "aku", not greet("aku"). Give a function fewer arguments than it needs and you get a new function that waits for the rest.
fn add a b = a + b inc = add 1 print (inc 41) # 42 double_all = map (fn x -> x * 2) print (double_all [1, 2, 3])
Errors are values
fail "msg" signals that something didn't work. or catches it on the same line, so there's no try or catch.
Real bugs, like adding text to a number, aren't caught by or, so they can't hide.
age = int "forty" or 0 nick = user.nick or user.name page = net.get url or fail "offline"
match takes things apart
Match on numbers, ranges, text, list shapes, record fields and types, with an if guard when a shape isn't enough.
match x
0 -> "zero"
1..9 -> "small"
[first, ...rest] -> "a list"
{ name } if name != "" -> "hi {name}"
_ -> "something else"
& runs it in the background
Like a terminal job: & starts work and hands you a job right away. wait gets the result, or the results of a whole list of jobs. Live streams work the same way: every 1000 | map f | each print runs in the background until you stop it.
tea = & brew "tea" 600 coffee = & brew "coffee" 900 wait [tea, coffee] | each print
Modules look like paths
The standard library lives under ~/io, your own files load with use ./name, and any npm package with use npm/name. JavaScript classes, methods, promises and callbacks all work from npx.
use ~/io/net use ./helpers use npm/discord.js use node/crypto
reference
- values
423.14"text {expr}"yesnonone[1, 2]{ name: "x" }1..10fn x -> x * 2- names
x = 1can't change.mut n = 0thenn <- n + 1can.[a, b] = pairand{ name } = usertake values apart.- functions
fn name a b = body, with optional types:fn add a:int b:int -> int = a + b. Types: int num text bool list rec fn none job any.retreturns early.- control
if c then a else bor an indented block,match,for x in xs,while c,break,next- truth
- Only
noandnonecount as false.0and""are values like any other. - lists
- map keep drop each fold find any all count sum min max first last take skip slice reverse sort sort_by uniq uniq_by flat zip push enum has len index_of chunk window group_by count_by sum_by min_by max_by
- text
- split join lines chars upper lower trim replace starts ends pad has len text int num
- records
- keys values get set has,
{ ...r, x: 1 },r1 + r2 - big numbers
- Whole numbers of any size:
123n,0xffn,big "1234…".+ - * // %and comparisons work, mixing with whole numbers; bit operations too.big_le bytesandle_bytes n xconvert to and from little-endian bytes. Typebig. - bits
- xor band bor bnot shl shr rotl rotr add32 sub32 mul32 u32 bits hex32. All work on unsigned 32-bit words.
- bytes
- hex unhex utf8 unutf8 words unwords, where bytes are a list of numbers 0 to 255
- streams
- Live values that flow through pipes: sources
every ms,events "name" emitter(any JS event emitter, a discord.js client included),stream list,merge [s1, s2].map keep drop take skipwork on streams;window n,debounce ms,throttle ms.s | each fruns it in the background and gives a job (wait job,stop job);collect sandfoldwait for the end. A failing item is reported and the stream carries on. - web server
- On the command line,
use ~/io/http:http.serve 8080 (http.router { "GET /users/:id": fn req -> { id: req.params.id } }). Handlers return text, a record (sent as JSON),{ status, body, headers }or none. A failing handler answers 500 and the server keeps running. - tests
- Top-level functions named
test_…in*_test.npxfiles are tests:fn test_add = expect (add 1 2) 3.expect_fail fchecks that f fails. Run them withnpx --test. - command line
npx file.npxruns a program;npx --test,npx --check,npx --fmt,npx --trace,npx --audit;npx --build file.npxmakes one.mjsfile that runs with plainnode, for copying to a server, andnpx --build --exe file.npxone program file with Node inside;npx --jsshows the compiled JavaScript;npxalone opens a prompt.- trace
- The Trace button (or
npx --trace file.npx) runs the program and shows the value after every|stage, with its line, so you can watch data flow through a pipeline. - format
- The Format button (or
npx --fmt file.npx) lays code out the standard way: 2-space indentation, spaces around operators and after commas. It never changes what the code does.npx --fmt --verifyonly reports, for CI. - playground
main.npxruns;+adds a file thatmain.npxloads withuse ./name. The JavaScript tab shows what the open file compiles to. Share keeps every file. Keys: ctrl+enter runs, ctrl+s formats, ctrl+/ comments lines.- web pages
use ~/io/page: a page is a function that answers elements; after every click or keystroke npx calls it again and updates what changed.page.show view,page.div [kids],page.h1,page.p,page.row,page.list,page.button "label" f,page.input { value, on_input: fn text -> … },page.link,page.img,page.el tag props kids,page.style css,page.refresh(). It shows in the Page tab here;npx --build --web file.npxmakes a standalone .html.- shared libraries
- On the command line,
npx --add github:user/repoadds a library anyone published, pinned innpx.json; thenuse lib/name.npx --installfetches them again and checks nothing changed. - check
- The Check button (or
npx --check) finds likely mistakes without running: too many arguments, a call on its own line missing arguments, type mistakes it can be sure of (text plus a number, a record field that doesn't exist, the wrong type for a typed parameter or-> type, comparing text with a number), a value named like a built-in then called, unused names anduselines (start a name with_to keep it unused on purpose). - audit
- The Audit button (or
npx --audit file.npx) lists what a program can touch (network hosts, files, environment variables, npm and Node modules, background work) without running it, following into libraries.allow net "discord.com"lines at the top of a file lock it to exactly that; anything else is refused. Kinds: net, read, write, env, npm, node. - other
- print show type fail attempt wait tap range repeat chunk round floor ceil abs.
attempt fruns f and returns{ ok, value }or{ ok: no, error }, catching bugs too. - npx libraries
use npx/discord: Discord bots as one record (commands, slash commands, events), with replies returned not sent, intents worked out for you, cooldowns, admin-only commands, anddiscord.testto try a bot without Discord.use npx/fetch: HTTP with JSON in and out, timeouts and retries:api = fetch.client { base: "https://…" },api.get "/users/1",api.post "/users" { name: "aku" }, andfetch.fakefor tests without a network. Beta, tested against stand-ins but not yet against the real services:use npx/csv:csv.parse textgives records (header row as field names),csv.text recordswrites CSV.use npx/mail(command line):post.send { to, subject, text }through Resend or SMTP.use npx/stripe(command line): Stripe payments.use npx/s3,npx/sheets(command line, beta): file storage on any S3-compatible service, and Google Sheets as records.use npx/kv: a key-value store,store.add "coins:aku" 25,store.set_for 60000 "cooldown:aku" yes,store.top "coins:" 3;kv.memory()here,kv.open "bot.json"on the command line.use npx/ai:model.ask,model.chatandmodel.jsonfor Claude and OpenAI-style APIs, withai.fakefor tests.use npx/telegram: Telegram bots as one record (commands, buttons, on.message), nothing to install,telegram.test bot "/start"to try one.use npx/cron: scheduled jobs,cron.run "0 9 * * mon-fri" f,cron.run "every 5m" f,{ when: …, zone: "Europe/Berlin" }for another time zone, daylight saving included,cron.upcomingto test a schedule.use npx/db(command line): SQLite with records in and out,bank.insert "users" { name: "aku" },bank.find "users" { vip: yes }, transactions.use npx/lattice: the LATTICE cipher.- npm
use npm/pkgloads any npm package;use node/fsloads Node's own modules (command line). Calling a JS class builds an object; JS methods, getters, promises and Map/Set loops work; npx functions passed to JS become callbacks: pure ones answer immediately (soarray.sortand lodash work), others answer with a promise (events, async APIs).typeof a JS object isjs. JavaScript's globals are in~/io/js:js.Date(),js.Map().- ~/io
- net (get post json request query), json (parse text pretty), math (with bytes for random bytes), time (now sleep date), date (now parse iso day parts add_days add_hours days_between). Command line only: fs (read write list exists), sys (args env exit).
where it stands
Works today
Everything on this page: the full syntax, pattern matching, typed functions, background jobs, bit operations and the standard library, covered by 134 tests. The same compiler runs here and on the command line.
Fast
npx compiles to JavaScript. Functions that only compute run as plain synchronous JavaScript, about 5 times faster again than 0.3 and within a few times of hand-written JS. The LATTICE cipher written in npx, including its authenticated mode with Poly1305 on big numbers, matches all 26 official test vectors in under a fifth of a second.
Still changing
Syntax can change before 1.0. If something reads wrong, or you'd write it differently, tell us.