v0.5 · MIT · one binary, written in Rust

The web, as a language.

Routes, request patterns, pipelines and HTML are part of Quillo's syntax, so a web app reads like a list of what it answers. Components render on the server and resume in the browser, with no build step.

app.qwe
route GET /hello/:name = `Hello, ${name}!`route POST /orders { json: { type: "order" | "refund", qty: int } } {    reply 201 { accepted: true, qty }}route GET /feed ? { page: int = 1 } =    request | auth.required | load_feed(page) | render_feed

The cells behind this page are Conway's Life: a Quillo component running in your browser. Move your pointer across them.

One binaryHTTP server, static checker, component compiler, SQLite and a language server.
~8 KB per pageGzipped, for a small component, and loaded only when someone reaches for it.
Expressions like JavaScriptArrows, ? :, template strings and JSX-style HTML, without the surprises.
Live by defaultPages follow the database over one WebSocket. No broker needed.

Tour

Everything a web app needs, in the syntax.

An app reads like a list of what it answers

  • Path parameters are variables; :id(int) matches only digits.
  • Query strings and JSON bodies are matched by patterns, with types and defaults.
  • | pipes a request through middleware, and reply answers from anywhere.
routes.qwe
route GET /hello/:name = `Hello, ${name}!`route POST /orders { json: { type: "order" | "refund", qty: int } } {    reply 201 { accepted: true, qty }}route GET /feed ? { page: int = 1 } =    request | auth.required | load_feed(page) | render_feed

Demo

The code on the left is the list on the right.

This page is a Quillo program. The component below was rendered on the server, and your browser took it over. Add an item, or click one to tick it off.

todo.qwe
component Todo() {    ~items = [        { id: 1, text: "Read the tour", done: true },        { id: 2, text: "Write a route", done: false },    ]    ~draft = ""    let left = items | filter((i) => !i.done) | len    <form.todo @submit={() => {        if trim(draft) != "" {            items = items + [{ id: len(items) + 1, text: draft, done: false }]            draft = ""        }    }}>        <input bind:value={draft} placeholder="Add something…"/>        <ul>{for i in items =>            <li key={i.id} class={i.done && "done"} @click={() => {                items = items | map((j) =>                    j.id == i.id ? merge(j, { done: !j.done }) : j)            }}>{i.text}</li>        }</ul>        <small>{left} left</small>    </form>}
  • Read the tour
  • Write a route
1 left

Speed

Numbers at native speed.

math, stats and vec give Python's exact answers, worked on by every core. How many times faster than Python 3.9, on a million floats (log scale; hover for timings):

  1. stats.stdev1037×Quillo 0.65 ms · Python 674 ms
  2. stats.mean611×Quillo 0.35 ms · Python 214 ms
  3. stats.describe449×Quillo 1.7 ms · Python 764 ms (by hand)
  4. stats.histogram210×Quillo 0.6 ms · Python 126 ms (a loop)
  5. stats.correlation176×Quillo 1.4 ms · Python 246 ms
  6. stats.linear_regression140×Quillo 1.3 ms · Python 182 ms
  7. stats.median34×Quillo 1.3 ms · Python 44 ms
  8. sort10×Quillo 4.6 ms · Python 46 ms

And more

Small language, whole toolbox.

Checked before it runs

quillo check holds the program to its types, list and map shapes, effects and error types, and warns about SQL built from values.

Safe by default

Text is escaped, cross-site posts are refused, sessions are signed cookies and javascript: URLs are blocked.

SQLite built in

Or PostgreSQL, with the same functions. Transactions nest, and migrations run in order, once.

Streaming

stream and events send an answer as it is made, from a CSV export to a model's reply word by word.

Translations

t("cart.items", { count }) picks plural forms by the language's rules, on the server and in components.

Services

Split a part of an app into its own server without changing its code; calls are signed with HMAC.

Numbers and data

math, stats and vec give Python's answers, on every core, in the server and the browser.

Desktop apps

quillo app runs the same program in a native window, with the platform's own web view.

Get started

From clone to running app in a minute.

terminal
$ git clone https://github.com/wisp-one/quillo.git && cd quillo$ cargo build --release$ ./target/release/quillo run examples/notes.qwe --watch

Then open http://127.0.0.1:8080. quillo check app.qwe finds mistakes without running, quillo repl tries things out, and the VS Code extension (or quillo lsp in any editor) adds diagnostics, hover and completion.

Quillo on GitHubRead the language tour →