PartnersOwn a database, an API or an SDK? Build its Quillo plugin with us

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

One HERO is not Awesome

One binaryHTTP server, static checker, component compiler, SQLite and a language server.
~12 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.

Ready to use

Bring what you need, it's already written.

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 } with db =    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() {    state items = [        { id: 1, text: "Read the tour", done: true },        { id: 2, text: "Write a route", done: false },    ]    state draft = ""    let left = items | filter((i) => !i.done) | len    <form.todo onsubmit={() => {        if trim(draft) != "" {            items = items + [{ id: len(items) + 1, text: draft, done: false }]            draft = ""        }    }}>        <input value={draft} placeholder="Add something…"/>        <ul>{for i in items =>            <li key={i.id} class={i.done && "done"} onclick={() => {                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 close to hand-written JavaScript in the browser.

Components compile to JavaScript with fine-grained signals: assigning state updates the places that show it, with no virtual DOM. In the keyed js-framework-benchmark app, driven in headless Chrome, each operation is timed from the click until the page is laid out. The total is the geometric mean of each time over the fastest one's, so 1.00 is the fastest and lower is better (hover for script time alone):

  1. Plain JS1.00×Plain JS: 1.00× the fastest in all, 1.00× in script alone
  2. Solid1.05×Solid: 1.05× the fastest in all, 1.82× in script alone
  3. Quillo1.09×Quillo: 1.09× the fastest in all, 2.10× in script alone
  4. Svelte1.17×Svelte: 1.17× the fastest in all, 2.08× in script alone
  5. Vue1.81×Vue: 1.81× the fastest in all, 9.01× in script alone
  6. Preact1.95×Preact: 1.95× the fastest in all, 6.11× in script alone
  7. React2.05×React: 2.05× the fastest in all, 6.76× in script alone
OperationPlain JSQuilloSolidSvelteVuePreactReact
Create 1,000 rows10.911.310.711.012.313.712.3
Replace 1,000 rows11.212.011.712.213.615.715.6
Update every 10th row2.302.702.402.403.602.902.80
Select a row0.1000.1000.1000.2001.000.4000.300
Swap two rows0.8000.9000.9001.001.8011.312.0
Remove a row0.8000.9000.9000.9001.901.101.00
Create 10,000 rows118129123125133157220
Append 1,000 rows12.213.112.312.315.115.714.5
Clear 1,000 rows1.101.201.201.301.401.502.90
Memory, 1,000 rows (MB)0.7812.011.692.053.863.173.71
Script, compressed (KB)inline12.66.5213.164.18.5058.2

Medians of several runs, on an Apple M-series laptop (10 cores) in headless Chrome. Run it yourself with node ui/run.js; the apps are in quillolang/benchmarks.

And serving faster than Node and Bun.

Requests a second from one process, kept busy by 64 connections from the same machine: plain text, JSON, TechEmpower's Fortunes without a database (sorted, escaped HTML, computed on every request) and a 10,000-step arithmetic loop, which Quillo compiles to machine code.

  • Quillo
  • Node 24
  • Bun 1.4
Plain text
  1. Quillo262k
  2. Node 24157k
  3. Bun 1.4225k

Quillo: 1.16× the next, 1.67× the slowest

JSON
  1. Quillo258k
  2. Node 24155k
  3. Bun 1.4227k

Quillo: 1.14× the next, 1.66× the slowest

Fortunessorted, escaped HTML, computed on every request
  1. Quillo180k
  2. Node 2489k
  3. Bun 1.4169k

Quillo: 1.07× the next, 2.02× the slowest

Compute10,000-step arithmetic loop
  1. Quillo26.4k
  2. Node 2424.4k
  3. Bun 1.423.4k

Quillo: 1.08× the next, 1.13× the slowest

Each server keeps about one core busy. Run it yourself with node server/run.cjs 8; the servers and the load generator are in quillolang/benchmarks.

And more

Small language, whole toolbox.

Checked before it runs

quillo check holds the program to its types, records, 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 or MySQL, with the same functions, and several at once. Transactions nest, and migrations run in order, once: the guide.

Real time, over UDP

Packets on a UDP port, messages to pages as WebTransport datagrams, a camera's RTP stream in any page, video calls from the pages' own cameras, answers streamed as they are made: the guide.

Translations

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

Microservices

Split a part of an app into its own server without changing its code. Calls are signed, retried, and run once: the guide.

Numbers, data and Rust

math, stats and vec give Python's answers on every core. For the rest, a .qwer file is Rust, called like any function: the page, and plugins to download.

Desktop apps

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

Exact decimals

0.1m + 0.2m is 0.3m. Decimals stay exact from the database to the page and back, and mixing one with a float is an error quillo check finds: the guide.

Money in any currency

money keeps amounts in their currency's minor units, never adds two currencies, splits a sum without losing a cent and writes it as each locale does: the guide.

Payments run once

idempotent gives a request sent again with the same key its first answer, with the work and the answer in one transaction: the guide.

Transactions that retry

db.transaction({ isolation: "serializable", retries: 5 }, f) runs f again when it collides with another transaction, on PostgreSQL, MySQL and SQLite: the guide.

Sponsors

Quillo is made in the open. Back it.

Sponsors pay for the language, the components, the plugins and the docs, and get a say in what comes next.

Become a founding sponsor

Get started

From clone to running app in a minute.

terminal
$ cargo install --git https://github.com/quillolang/quillo quillo$ git clone https://github.com/quillolang/examples.git && cd examples$ quillo run notes.qwe --watch

Needs Rust 1.94+ and a C compiler: what to install on macOS, Linux and Windows. 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.

Questions, ideas, something you made? Come say hi on Discord or r/quillo.

Story

  1. 2024Conceived: what if routes, patterns and HTML were the language itself?
  2. Late 2025The first prototype: a tree-walking interpreter in Rust, serving its own routes.
  3. October 2026v0.5: components that resume in the browser, a static checker, live data and a language server.
  4. 29 October 2026v0.6: private names, plugins taken by name, quillo install and 628 plugins.
  5. 5 November 2026v0.7: shared hosting through FastCGI and Unix sockets, a host's policy on what a program may do, and SQLite queries faster than Python's.
  6. 7 November 2026v0.8: one visitor's data never reaches another, a key of idempotent runs once whoever asks, numbers exact or an error, and the latest call wins.