A cross-platform terminal, built for speed and efficiency.
Linux, Windows and macOS — iOS coming soon. Measured faster than ghostty on Linux and macOS, and Windows Terminal on Windows, at about half the CPU. Below: each pair on one machine, matched grids, three tests, one take.
Wayland or X11 on Linux, a native Win32 window on Windows, a Cocoa window on macOS — the same terminal, and the same speed, on each. iOS is next.
Ten workloads at steady state: 1.41× Windows Terminal on Windows, 1.38× ghostty on Linux, 1.28× ghostty on macOS — matched grid and font, at about half the CPU each time.
Zero ucs-detect errors in 107k+ measurements — wide characters,
emoji families, 118 languages of conjuncts — where the ghostty nightly
logs 40.
curl -LO https://github.com/starling-build/starling/releases/download/terminal-v0.1.0/starling-terminal_0.1.0_amd64.deb
sudo apt install ./starling-terminal_0.1.0_amd64.deb
Everything the terminal loads — engine, Swift runtime,
fonts — rides inside the package under
/usr/lib/starling-terminal; apt resolves the
few system libraries. It opens from the app grid as
Starling Terminal, or as starling-terminal
from any prompt. On the Starling desktop there
is nothing to install — the terminal is part of the desktop.
curl -LO https://github.com/starling-build/starling/releases/download/terminal-v0.1.0/starling-terminal-0.1.0-macos-arm64.zip
ditto -xk starling-terminal-0.1.0-macos-arm64.zip /Applications
Or unzip it and drag Starling Terminal.app
into Applications yourself. The bundle is signed but not notarized, so
macOS holds the first launch: approve it under System Settings →
Privacy & Security → Open Anyway, or clear the
quarantine bit with
xattr -dr com.apple.quarantine "/Applications/Starling Terminal.app".
curl.exe -LO https://github.com/starling-build/starling/releases/download/terminal-v0.1.0/starling-terminal-0.1.0-windows-x86_64.zip
Expand-Archive starling-terminal-0.1.0-windows-x86_64.zip -DestinationPath StarlingTerminal
.\StarlingTerminal\TerminalApp.exe
A native Win32 window, no installer and nothing to put on
PATH. Give it a folder of its own: the archive extracts
flat, and all 52 files have to stay together — Windows
resolves imports from the executable's own directory, and the bundled
ConPTY console host sits beside it.
Thirteen tests — ten workloads, two 500 MB cats, DOOM-Fire — against the fastest terminal on each platform. Matched fonts, grids verified on both sides, every test at steady state. Amber, rightward — Starling is ahead; grey, leftward — the other terminal is. The setup and every raw number are below the charts.
Speed — thirteen tests at steady state, three platforms
Hover any row for the raw seconds. Sustained is the regime that
matters, and it is not always the flattering one — the two workloads ghostty
wins in ten-second bursts (light and dense cells, 0.85× and 0.69×
short-range) converge to parity here, but ghostty also gains nothing back:
its Linux unicode throughput halves at scale (184 to 97 MB/s) while ours
sheds only a quarter (228 to 173 MB/s). Across all three platforms and all
thirty-nine cells above, the one test the other side keeps by more than
noise is the Linux ascii cat, by ~6% — ghostty's
io_uring read path gets under the read(2) floor
ours sits on. macOS has no io_uring, and the cat flips to us; on Windows
every test is a win.
The cost — CPU and memory for the same work
The wall wins are not bought with cores. In ten-second bursts the gap is wider still: 2.17× and 3.37×.
On Windows the CPU figures include the console host, which does a large share of the work there and would flatter us if left out; the memory gap is the widest of the three platforms — 73 MB against 1,026 MB after the same ten workloads, a figure Windows Terminal reproduces across machines. CPU-seconds are otherwise charged to the terminal's own process, read around each workload. Memory is flat on our side of all three platforms — the same resident set no matter how much has been drawn — while the other side's grows with load; only the light Linux legs leave ghostty below us.
The setup
Who: the ghostty nightly on Linux and macOS, configured onto our Roboto Mono at our cell metrics so both terminals raster the same pixels; Windows Terminal Preview 1.25 on Windows, in its own process (the stable build hands new windows to whatever Windows Terminal is already running). Where: Linux — Ryzen 7 8845HS, GNOME/Wayland; macOS — MacBook Pro on macOS 26.6.1; Windows — a Ryzen 7 8845HS laptop with a Radeon 780M, the first Windows round on real hardware rather than a VM. Grids verified on both sides before every leg: 47×201 on Linux and macOS, 40×120 on Windows. How: every test at steady state — each workload repeated until the slower side sustains one to two minutes (~159 GB of escape-sequence traffic per terminal on Linux, ~30 GB on macOS), the cats exact 500,000,000-byte corpora, DOOM-Fire run to 150,000 frames three times over. Both sides measured back to back on one machine; bars are multiples of the other terminal's pace on a log scale, so a 2× win and a 2× loss have equal length.
The rounds behind the numbers
The Linux and Windows legs ran on 30 Hz displays, so raw walls compare
within a platform; the ratios carry. The macOS numbers are the rerun taken
after the macOS 26.6.1 upgrade — which moved nothing beyond run noise
against the same-day pre-upgrade round. The Windows round runs the console
on the UTF-8 code page, so the unicode workloads draw real CJK text rather
than the mojibake every earlier VM round was unknowingly measuring, and a
fixed compute loop timed inside every leg proves both sides saw the
machine in the same state; the archived VM rounds remain, but they measure
the legacy code page. The raw runs are checked in at
docs/perf
(Windows: -windows-realgpu-2026-08-16; Linux:
-2026-08-14-long; macOS:
-macos-2026-08-14-postupgrade, confirmed against
-macos-2026-08-14-long; short range:
-2026-08-13-atlas and
-macos-2026-08-13-samefont).
Raw speed — seconds to drain each workload
| Linux | macOS | |||||
|---|---|---|---|---|---|---|
| Workload | Starling | ghostty | Speedup | Starling | ghostty | Speedup |
| Light cells | 0.586 | 0.497 | 0.85× | 0.111 | 0.149 | 1.34× |
| Dense cells | 0.249 | 0.173 | 0.69× | 0.129 | 0.145 | 1.12× |
| Coloured text | 0.387 | 1.039 | 2.68× | 0.438 | 0.642 | 1.47× |
| Truecolour | 0.390 | 0.761 | 1.95× | 0.619 | 0.713 | 1.15× |
| Unicode | 0.334 | 0.316 | 0.95× | 0.323 | 0.305 | 0.94× |
| Cursor motion | 0.022 | 0.034 | 1.55× | 0.031 | 0.037 | 1.19× |
| Alt screen | 0.117 | 0.135 | 1.15× | 0.207 | 0.180 | 0.87× |
| Scroll region | 0.510 | 0.457 | 0.90× | 0.181 | 0.217 | 1.20× |
| Long lines | 0.145 | 0.147 | 1.01× | 0.163 | 0.181 | 1.11× |
| Binary dump | 0.479 | 1.624 | 3.39× | 0.189 | 0.545 | 2.88× |
| All ten workloads | 3.219 | 5.183 | 1.61× | 2.391 | 3.114 | 1.30× |
Seconds compare within a platform, not across it: the Linux round ran on a 30 Hz display, which slows both terminals' absolute times equally. The ratios carry.
CPU — what the suite costs the machine
| Ten workloads | Starling | ghostty | Speedup |
|---|---|---|---|
| Linux | 4.46 s | 9.66 s | 2.17× |
| macOS | 2.38 s | 8.02 s | 3.37× |
Memory — resident set
| Sampled at | Starling | ghostty | Delta |
|---|---|---|---|
| Linux, after the suite | 225 MB | 209 MB | +16 MB |
| Linux, after 159 GB of suite | 225 MB | 212 MB | +13 MB |
| Linux, after two 500 MB cats | 225 MB | 256 MB | −31 MB |
| macOS, after 30 GB of suite | 121 MB | 155 MB | −34 MB |
| macOS, after two 500 MB cats | 121 MB | 177 MB | −56 MB |
The macOS rows are the 08-13 long round, the one macOS round that sampled RSS at both points. The current build measures 130 MB against ghostty's 155 after the suite — the paced reader's 8 MB ring and thread stacks — and stays flat the same way.
Steady state — every test run for minutes, not seconds
| Linux | macOS | Windows | |||||||
|---|---|---|---|---|---|---|---|---|---|
| Test | Starling | ghostty | Speedup | Starling | ghostty | Speedup | Starling | Win Terminal | Speedup |
| Light cells | 101.2 s | 102.0 s | 1.01× | 53.9 s | 96.9 s | 1.80× | 142.7 s | 170.1 s | 1.19× |
| Dense cells | 86.8 s | 86.2 s | 0.99× | 92.0 s | 96.7 s | 1.05× | 97.3 s | 129.6 s | 1.33× |
| Coloured text | 34.0 s | 108.3 s | 3.19× | 76.9 s | 112.4 s | 1.46× | 179.7 s | 188.8 s | 1.05× |
| Truecolour | 54.2 s | 122.8 s | 2.27× | 81.1 s | 106.5 s | 1.31× | 163.5 s | 215.4 s | 1.32× |
| Unicode | 97.1 s | 107.3 s | 1.10× | 81.9 s | 98.3 s | 1.20× | 96.6 s | 146.0 s | 1.51× |
| Cursor motion | 49.9 s | 74.3 s | 1.49× | 70.4 s | 71.2 s | 1.01× | 177.4 s | 203.0 s | 1.14× |
| Alt screen | 80.8 s | 85.9 s | 1.06× | 88.8 s | 88.4 s | 1.00× | 118.6 s | 222.3 s | 1.87× |
| Scroll region | 80.4 s | 78.5 s | 0.98× | 90.3 s | 96.6 s | 1.07× | 167.0 s | 222.7 s | 1.33× |
| Long lines | 85.0 s | 84.3 s | 0.99× | 93.7 s | 97.3 s | 1.04× | 102.7 s | 136.0 s | 1.32× |
| Binary dump | 26.7 s | 109.9 s | 4.12× | 31.8 s | 110.1 s | 3.46× | 40.9 s | 177.6 s | 4.34× |
| All ten workloads, wall | 696 s | 960 s | 1.38× | 761 s | 974 s | 1.28× | 1286 s | 1812 s | 1.41× |
| All ten workloads, CPU | 1030 s | 1930 s | 1.87× | 1081 s | 2436 s | 2.25× | 1581 s | 3182 s | 2.01× |
| ascii cat, 500 MB | 2.97 s | 2.79 s | 0.94× | 1.82 s | 2.01 s | 1.11× | 1.98 s | 2.71 s | 1.37× |
| unicode cat, 500 MB | 2.88 s | 5.15 s | 1.79× | 1.76 s | 2.45 s | 1.39× | 4.40 s | 6.46 s | 1.47× |
| DOOM-Fire, 150,000 frames | 1610 fps | 830 fps | 1.94× | 1119 fps | 1071 fps | 1.05× | 482 fps | 390 fps | 1.24× |
Cats and DOOM-Fire at short range — 150 MB cats
| Linux | macOS | |||||
|---|---|---|---|---|---|---|
| Test | Starling | ghostty | Speedup | Starling | ghostty | Speedup |
| ascii cat, 150 MB | 0.869 s | 0.829 s | 0.95× | 0.611 s | 0.692 s | 1.13× |
| unicode cat, 150 MB | 0.659 s | 0.815 s | 1.24× | 0.806 s | 0.826 s | 1.02× |
| DOOM-Fire | 1200 fps | 701 fps | 1.71× | 1058 fps | 960 fps | 1.10× |
Raw values are seconds for the cats and frames per second for DOOM-Fire; the speedup is Starling's multiple either way. The fire rows run 600 frames on Linux and 6,000 on macOS — at 600 the macOS pair reads ~1025 vs ~845 fps (1.21×), but the longer run amortizes ghostty's warm-up and is the fairer number. CPU is ours on all six legs — ghostty spends 1.4–2.8× as much.
The emulator is about 2,000 lines of C we wrote — no libvte, no libvterm, nothing borrowed. The pixels come from the Flutter engine through the Starling SDK: a general-purpose UI engine, not a terminal-specific one.
That is the unusual part. Terminals this fast are normally built on a stack that can only ever draw a terminal. This one matches or beats them on their own benchmarks — and the engine underneath hands us the rest for free: the same code on every platform, and a real widget tree around the grid, which is where the splits, the floating frames and the cover flow come from.
The Starling SDK has a terminal widget — shell, escape sequences, fonts, scrollback and selection included — so you can write your own terminal app on top of it. Download one file, run it, and you have a terminal of your own, on Linux, macOS or Windows:
curl -fLO https://github.com/starling-build/starling/releases/download/sdk-v0.3.0/starling-create
chmod +x starling-create
./starling-create myterm
cd myterm && swift run -c release
Those four lines are the same on Linux, macOS and Windows
— on Windows in Git bash, which is where a curl instruction
lands anyway. starling-create is an asset on the release
above, the same one the terminal itself ships from. It checks your
toolchain, fetches the SDK bundle for the machine it is run on — the
framework plus the engine binaries it links against, 14 MB on macOS,
17 MB on Windows, 23 MB on Linux — and writes the SwiftPM project
around it. No repo to clone, no engine checkout, no Flutter install; a
Swift toolchain is the only prerequisite. The SDK is cached once under
~/.starling/sdk and shared, so the second project costs no
download; --template app scaffolds a plain window instead of
a terminal, and --sdk takes a URL or a local archive when you
want a bundle other than the release's. What it writes is this, and this
is the whole app:
import ExampleHost
import Flutter
let session = TerminalSession()
session.startShell()
runExampleApp(title: "Terminal", width: 940, height: 620) {
TerminalView(session: session)
}
That is the same widget the films above run on, and the same one the shipped terminal is built from — the release archives are assembled against this SDK bundle, not against a private tree. The workspace is it with geometry around it — splits, frames and a cover flow, and no terminal code of its own.