Xo is experimental. The source is now public on GitHub, or try Xo in your browser.
Menu · Xo and Python

Docs

Xo and Python

On this page

Part of the comparison series that starts with Xo and Go. It is not a “which is better” page. Python is one of the most used languages there is, with a huge ecosystem for data, scripting, machine learning and web services, and it is fast to write. Xo is an experimental compiled language. This page compares writing a backend in each, including the place where Python’s standard library server did better than Xo: CPU per request.

Versions. Claims about Python are checked against the Python documentation as of Python 3.15.1 (the newest release, 2026-10-21). The measurements used CPython 3.13.12 from Homebrew, with the packages pinned with hashes in the benchmark’s requirements.txt (uvicorn 0.37.0, uvloop 0.23.0, httptools 0.9.0, Starlette 0.48.0); they will be rerun on a current release. The Xo in the measurements is a build of main between 0.26.0 and 0.27.0 (it reports itself as 0.26.0). Last verified: 2026-10-23.

Short version

Choose Python when the work is scripting, data, or machine learning, when a library you need exists only for Python, when the team knows it, or when the speed of writing matters more than the speed of running. It is mature, everywhere, and production proven; Xo is experimental (spec draft 0.10, no 1.0 yet).

Consider Xo when the service is CPU bound or concurrent, when you want types the compiler enforces, errors in function signatures, every core in one process, and one static binary to deploy. In the measurements below Xo was 4 to more than 100 times faster than CPython on compute, concurrency and JSON, and served 1.6 times the requests of Python’s asyncio server, but asyncio used about two thirds of Xo’s CPU per request and had lower tail latency.

What each is for

  • Python: “a programming language that lets you work quickly and integrate systems more effectively” (python.org).
  • Xo: backends, tools, and web services, designed so AI agents can write, check, cross compile, and debug programs with fast, structured feedback (Why Xo?).

The language

PythonXo
TypesDynamic. “The Python runtime does not enforce function and variable type annotations”; type checkers, IDEs, and linters use them (typing)Static, checked by the compiler; a program that does not check does not build or run
Absent valuesNone, which any variable can holdNo null; T? is Option[T], and the compiler makes you handle None (core 2.5)
ErrorsExceptions; a function’s signature does not say what it raisesT ! E; an unhandled Result does not compile; ? propagates and records an error trace (core 2.6, 11.1)
Sum typesClasses and unions in annotations; match (since 3.10) with no exhaustiveness check at run timeEnums with payloads and exhaustive match, with guards (core 2, 3)
Integers“Integers have unlimited precision” (built-in types)Int is 64 bit and overflow faults; BigInt in std/big (core 2.1, std 33)
ValuesObjects, lists, and dicts are shared referencesValue semantics with copy-on-write; mutation is visible in signatures (var parameters) (core 5)
Concurrencyasyncio tasks on one thread; threads under the global interpreter lock; multiprocessing for more cores. A free-threaded build without the GIL exists since 3.13 as an optional build, with 1% to 8% overhead on single-threaded code (free threading)Tasks spread over every core in one process; structured concurrency (scope), cancellation without a parameter, channels, select, Mutex (core 7)
Side effectsNot in signaturesEffects in signatures (uses (net, fs)), capability values passed from main, and fakes for tests (core 6)

Memory

  • CPython uses reference counting, with a collector that “supplements the reference counting” to free cycles (gc).
  • Xo native builds use reference counting too, with no cycle collector: value semantics leave no cycles. HTTP handlers get request scoped arenas by default (FAQ, core 10).
  • Measured: Xo’s programs peaked at 0.11 to 0.29 of Python’s memory on every row; the asyncio CRUD server peaked at 23.1 MB against Xo’s 19.1 MB (sources below).

Safety and security

PythonXo
Type errorsFound at run time, or before it by an external type checkerFound by the compiler
Data racesThreads take turns under the GIL; shared state still needs a threading.Lock, and the optional free-threaded build runs threads in parallelValues never alias mutably, so data races are impossible except through Mutex and Atomic, which are synchronized (core 5)
Integer overflowNone: integers growFaults: a bug report, not a wrong number (core 2, 8)
CapabilitiesAny package can use the file system, network, and processesCode reaches the file system, network, environment, or processes only through capability values it was given; a module can be held to a ceiling (uses none) (core 6, Dependencies)
Supply chainpip’s hash-checking mode (--require-hashes) protects against tampering; by default installing “involves running arbitrary code from distributions” (secure installs)xo.lock hashes each module version; no dependency code runs at fetch or build setup (decision 0156); an effect lock fails an update that adds an effect until accepted, and xo audit lists each dependency’s effects (Dependencies). There is no vulnerability database yet

Toolchain and deployment

  • Running code. Python runs source directly, with no build step. Xo compiles to a native binary first (xo run does both).
  • Deploying. A Python service ships its source, its packages (often in a virtual environment or container), and an interpreter. Xo ships one static binary, and xo build --targets=all cross compiles for linux, darwin and windows on arm64 and x86-64, plus WASI, from any host (core 11).

Build, size and startup (the CRUD server of the benchmarks below and a hello program; CPython 3.13.12; Apple M4 Pro, 2026-10-24):

Pythonxo 0.29.0
Before the first runnothing to build; the first import of the server compiles it to bytecode: 0.04 to 0.07 sa 2.3 s cold build
After an editthe next import recompiles the module: 0.04 to 0.07 sa 0.50 s build
What ships7.9 KB of server source, 25.8 MB of installed packages (uvicorn, Starlette, uvloop, httptools), and a 77.7 MB interpreter installationa 2.3 MB binary (xo build --release; 6.2 MB with debug information)
Hello startup, wall17.5 ms2.7 ms (0.153 of Python’s)
Hello startup, peak memory13.9 MB2.6 MB

Source: twins-build-2026-10-24.md, lines 20, 28 to 29, 39 to 40, 52 to 54 and 70 to 73. Python has no build to wait for; Xo’s build costs seconds once and about half a second after a change, and in return its program starts 6 times faster and ships as one file.

Writing it with AI agents

Python is the language models know best, and agents write it fluently. Its weakness for an agent is that many mistakes show up only when the code runs. Xo is designed for the agent’s loop:

  • xo check --json reports every problem with a stable XOnnnn code and machine-applicable fixes; codes never change meaning (diagnostics).
  • Python habits (def, elif, True, None, print, range, comprehensions, lambda, **, f-strings, and others, 29 cases) get a diagnostic that names Python and gives the Xo form, with a fix.
  • xo def, xo refs, xo query, xo edit, and xo mcp answer semantic questions and make edits through resolved symbols.

Benchmarks

Method. The same programs written twice, each in its own language’s idiom (Python: asyncio tasks for spawn, fanout and ping-pong, 8 threads under threading.Lock for mutex, multiprocessing with one process per CPU for parallel map, json.loads and json.dumps), and run under xo bench --ab with Python as A and Xo as B, interleaved rounds; a verdict is “better” or “worse” only when the 95% interval excludes 1.0. The fib and parallel map rows ran 3 rounds because one Python run takes seconds (“too few rounds” in the file): read those as orders of magnitude. Every program prints a checksum and the run stops if Python’s and Xo’s differ. There is no rwmutex row: the standard library has no read write lock. Machine: Apple M4 Pro (12 cores), macOS 27, darwin/arm64, with other jobs running (each row waited for a load under 5). Versions: CPython 3.13.12 with the GIL; Xo from main between 0.26.0 and 0.27.0, native backend. Date: 2026-10-23. Ratios are Xo over Python; under 1.0 means Xo took less (python-vs-xo-2026-10-23.md, lines 1 to 11 and 99 to 104).

workloadwall time, Xo / Pythonverdictsource
ping-pong0.009betterline 34
parallel map (multiprocessing)0.0193 roundsline 44
fib (recursive, 40)0.0253 roundsline 16
JSON encode0.13betterline 62
spawn0.135betterline 24
mutex0.15betterline 39
fanout0.165betterline 29
JSON decode0.25betterline 52

Xo’s tasks use more cores than Python’s: on spawn and fanout Xo used 0.51 and 0.63 of Python’s CPU against 0.135 and 0.165 of its wall time (lines 25 and 30).

HTTP: the users CRUD API, given twice for Python: the standard library’s asyncio.Protocol, and Starlette on uvicorn with uvloop and httptools, each in one process, against Xo’s std/http with request arenas; 32 workers on loopback, 10 s measured after a 2 s warmup, the median of 3 runs (lines 89 to 96):

Python asyncioPython StarletteXoXo / asyncio
requests/s82,79832,782134,4681.62
p50 latency349 µs925 µs201 µs0.58
p99 latency906 µs1,970 µs937 µs1.03
p99.9 latency1,618 µs4,028 µs2,316 µs1.43
server CPU per request11.80 µs30.30 µs18.03 µs1.53
peak RSS23.1 MB37.6 MB19.1 MB0.83

Python’s asyncio server used less CPU per request than Xo, in all three runs (11.71 to 12.22 µs against Xo’s 17.94 to 18.50; lines 76 to 87), and its p99.9 latency was lower in all three. It is the standard library’s low-level protocol API on one thread, with no framework; Xo’s server spreads connections over every core, which bought 1.6 times the throughput at that CPU cost. A Python service written with a framework is closer to the Starlette column: Xo served 4.1 times its requests at 0.60 of its CPU per request.

These are a young compiler’s numbers on one machine. The comparison is rerun from bench/perf/python/run.sh and this page’s tables are refreshed from its results file.

↑ index