Wisp

Type to search every docs page and heading.

Tokens

Most app code is written by AI, so an app's cost is measured in tokens, and keeping it low is a Wisp principle (design). Run cargo run -q -p wisp-tokens --release for the numbers. The four-app comparison against six frameworks: Tokens, app by app.

Five Features, Counted by wisp-tokens

bench/tokens/apps holds the same five features as a complete app in each stack:

  • a list page loading its data
  • a contact form (name 1 to 50 characters, a valid email; a 422 that shows each problem and keeps what was typed, else a redirect). Every stack checks the same two rules with the same two messages, hand-written where the framework has no rule, and Wisp's are built in
  • a JSON endpoint of the list
  • a layout with a nav
  • a live search filtered in the browser

cargo run -p wisp-tokens counts them (method below, in bench/tokens/src/main.rs, with characters / 4 beside it). A @feature NAME comment says whose its lines are; a file without one, as a generator writes it, is not counted, nor the [package] table cargo new writes.

The Node apps: Nuxt is file routes, server routes in server/api and useFetch, the form posting with $fetch; Express renders EJS views with a shared header and footer and a small script for the search; React is a Vite app with React Router, useState and fetch, over a small Express API. Their generated package.json, nuxt.config.ts and index.html are not counted; the proxy line added to vite.config.js is. The Wisp app builds with the workspace, and its tests check each feature.

Stacklistformapilayoutsearchdatasetuptotalchars / 4files
Wisp5889316011111504642836
SvelteKit 212842557831927209576209
Next.js 15107400441082417109717068
Nuxt 4 (Vue)9642922961587108725968
React 19 (Vite + Express)1085203226819116110213829998
Express 5 + EJS12842334116291699511566997
Axum 0.8 + askama14555329104217123285145610217
Actix Web 4 + tera16456546104237123292153110617

Wisp's data is longer than JavaScript's: a Rust type with its fields' types and pubs. Everything else is shorter, the form most of all. Of what is left, 60 tokens are file paths, 115 the Rust type and data, and the rest is markup every stack writes.

A Real App: Auth, CRUD, Upload, Live, a Component

bench/tokens/real is sign up and in, a posts table with validation, edit, delete, pages and live refresh, an avatar upload and a toggle component: 10 files, 995 tokens in Wisp, 3.5x less than SvelteKit 3 and 3.3x less than Next.js 15. Its tests check every feature.

Method

Counted: every file a developer (or an agent) writes by hand, beyond what the framework's generator gives, plus each file's path (writing a file means naming it, so two files cost more than one). Manifests (Cargo.toml, package.json) are left out everywhere.

There is no tokenizer offline, so the count estimates a BPE code tokenizer (cl100k-like):

  • a newline with its indentation is 1 token; spaces join the word after them
  • identifiers split at _ and camelCase humps, each part 1 token up to 8 letters and 1 per 6 after that
  • digits 1 per 3
  • common operators (:: -> => == </ /> {{ <%= ...) 1; any other punctuation character 1

Characters / 4, the usual rule of thumb, ranks the frameworks the same way.

Competitor versions: SvelteKit 2 with Svelte 5 runes and use:enhance; Next.js 15 app router with server actions and useActionState; Nuxt 4 with server routes and useFetch; Express 5 with EJS; React 19 with Vite and an Express API; Axum 0.8 with askama; Actix Web 4 with tera. The Wisp versions are built by a script, so every counted line compiles. Every competitor app's source is in bench/tokens/apps.

Is This Page Useful?

Edit This Page