PAX: Compiling Perl Again, This Time for Real

2026-04-24

Perl developers have heard "compiled Perl" claims for a long time. Most of them ended in one of three places: a benchmark trick, a startup shortcut or a demo that could not survive real application code.

That history is exactly why PAX is worth looking at carefully instead of cheering too early.

PAX is not a new language and it is not a pitch to replace Perl with something trendier. The point is more specific than that: keep Perl, compile what is actually safe to compile, preserve Perl behaviour where the language stays dynamic, package the result into one executable and make eligible hot paths run at native speed.

That is a much harder goal than "transpile a toy script," but it is also the only goal that matters if you want working developers to take the project seriously.

Why This Conversation Usually Fails

Perl is not a shallow language. A real compiler story has to deal with all the things that make Perl powerful and awkward at the same time:

  • context sensitivity
  • runtime symbol table mutation
  • imports with side effects
  • require, eval, caller, prototypes and magic variables
  • top-level script behaviour that does not reduce cleanly to one function call

If a tool only works on the easy tenth of the language, it is not solving the problem the Perl community actually has.

That is why most old "compiled Perl" conversations died on contact with production code.

What PAX Is Trying to Do Differently

The important thing about PAX is not that it claims to compile Perl. The important thing is the shape of the system around that claim.

PAX combines:

  • captured Perl code structure and runtime metadata
  • compiled code units where the semantics are understood well enough
  • hybrid units where some parts can compile and some still need a compatibility path
  • embedded assets
  • standalone binary packaging
  • native dispatch for hot regions that qualify

The compact version looks like this:

terminal
Perl app + Perl modules + assets + PAX compiler/runtime
-> one generated executable
-> runs without the source tree
-> can execute eligible hot paths natively

That is a very different target from "make one loop faster."

The Part That Makes It Credible

The strongest idea inside PAX is that it does not force an all-or-nothing compiler fantasy.

Real Perl applications are uneven. Some modules are stable and compiler-friendly. Some are not. Some families of code can be lowered deeply. Others still need a compatibility floor. PAX treats that as a systems boundary to manage instead of pretending the hard parts do not exist.

Right now that shows up in multiple packaged code-unit forms, including compiled units, hybrid compiled units and specialized compiled entrypoint families for scripts and webapp dispatch.

That matters because it gives the project a plausible way to move forward incrementally without throwing the whole application back to "just run the source" every time one module gets weird.

What Already Works

This is the part that changes the tone of the discussion.

PAX can already:

  • build standalone executables
  • use paxfile.yml as a repeatable build contract
  • package compiled and hybrid Perl code units
  • embed assets
  • package native hot-path artefacts
  • use bundled-runtime compatibility where the compiler frontier has not reached a dependency yet

That still would not be enough by itself if it only worked on synthetic cases. The more interesting evidence is that the project already has a real web application path.

The Web App Proof Matters More Than the Benchmark

PAX now supports a reference web application built around the sort of stack Perl developers actually recognize:

  • Dancer2
  • Plack
  • Starman
  • Template Toolkit
  • TT templates
  • CSS
  • JS

That application is built as one standalone binary and the binary still serves the pieces you expect from a real app, including rendered HTML, CSS, JS and a health endpoint.

The build path is concrete:

terminal
perl -Ilib bin/pax standalone-build --compact --paxfile examples/webapp/paxfile.yml

The resulting binary can then be run directly:

terminal
.pax/standalone/pax-webapp/pax-webapp serve --host 127.0.0.1 --port 5000

There is also a proper two-stage Docker story:

terminal
FROM perl-build-image AS build
# install deps, copy repo, build PAX binary

FROM debian:trixie-slim
COPY --from=build /workspace/.pax/standalone/pax-webapp/pax-webapp /app/pax-webapp
ENTRYPOINT ["/app/pax-webapp"]

That stage-two image gets the binary, not a checked-out application tree. For anyone who has spent years shipping Perl by dragging source trees and runtime assumptions through deployment, that is the part worth paying attention to.

PAX vs PAR and pp

This is the first serious question Perl people should ask, because pp -o foo foo.pl already exists.

PAR and pp are mainly about packaging Perl applications into a runnable bundle. That is useful and for some deployment jobs it is enough. If all you need is "take this Perl program, include the interpreter and modules and hand me one artefact I can move around," PAR already has a real answer.

PAX is trying to move the execution model itself forward.

The difference is not just "single file or not." The difference is what is inside that file and what the runtime can do with it.

With PAR, the usual story is closer to:

  • package the script
  • package the interpreter and dependencies
  • unpack or bootstrap them at runtime
  • still execute Perl through the normal interpreter path

With PAX, the target is broader:

  • compile application code into packaged code units where the semantics are understood
  • keep hybrid units when only part of a module can be lowered safely
  • carry compatibility metadata and bundled fallback runtime behaviour for the dynamic parts
  • dispatch eligible hot paths to native artefacts instead of only interpreted execution

That is why the PAX post keeps emphasizing compiled units, hybrid units, compatibility floors, native dispatch and standalone inspection. Those are not normal pp talking points.

So the practical answer is:

  • if you want packaging, PAR already matters
  • if you want adaptive compilation plus packaging plus native-speed hot paths, that is the space PAX is aiming at

The reason this is interesting is that PAX is not trying to replace Perl with a fake static language. It is trying to package and accelerate real Perl applications while keeping a correct compatibility path where the language stays dynamic.

PAX vs perlcc

This is the second hard question and it is a fair one.

Perl developers have already seen this movie. perlcc died because compiled Perl kept breaking on the exact dynamic behaviours that real applications rely on. That is why a lot of people hear "compiled Perl" and assume the ending has already been written.

That history should make people stricter, not softer.

The main difference is that PAX is built around an explicit hybrid model instead of an all-or-nothing compiler promise.

That matters because perlcc-style thinking tends to fail at the same boundary every time:

  • dynamic language features are treated as a problem to eliminate
  • the hard cases pile up
  • real applications hit those hard cases immediately
  • the compiler either breaks semantics or gives up

PAX is trying to survive that boundary differently.

Instead of assuming the whole application can be lowered cleanly, it separates the runtime into pieces:

  • compiled code units where the behaviour is stable enough
  • hybrid units where only part of the module can be lowered safely
  • bundled runtime and compatibility metadata for the dynamic residuals
  • native dispatch for eligible hot regions without pretending all code is native

That does not guarantee success. It does explain why PAX is not simply repeating the old perlcc bet.

The old failure mode was roughly: "compile everything or lose." The PAX model is closer to: "compile what is defensible, keep a correct compatibility floor for the rest and still make the packaged result deployable."

That is a much more realistic strategy for Perl as it actually exists.

So will PAX automatically avoid perlcc's fate? No. It still has to keep moving the compiler frontier in ways that hold up across real applications.

But the reason it deserves attention now is that the project is no longer relying on the same fragile premise. It already has a standalone binary path, bundled runtime behaviour, hybrid packaged units and native dispatch for the code that really qualifies. That is a more credible systems story than "trust the compiler harder this time."

PAX vs Rust

This question also needs a blunt answer.

Rust is the stronger choice if you are starting a new performance-critical system and are willing to build it as Rust from the beginning. PAX is not the argument you make when you want to beat Rust at being Rust.

The reason PAX matters is different.

Most teams asking about PAX do not have a blank greenfield. They already have a Perl codebase, already have deployment habits, already have dynamic framework usage and already know that a full rewrite is expensive, risky and often politically unrealistic.

In that situation, "just rewrite it in Rust" is not always a serious answer. It is often a different project entirely.

So the useful comparison is not:

  • Rust vs PAX in a language beauty contest

It is:

  • what can you do if the system is already Perl and you want better deployment plus more native-speed execution on the parts that qualify

That is where PAX is trying to help.

Rust gives you a native language and a native toolchain.

PAX is trying to give you:

  • a standalone deployment story closer to native-language tooling
  • native dispatch for eligible hot paths
  • a compatibility floor for the dynamic Perl you are not going to erase overnight
  • a path to improve performance without demanding a rewrite first

So is PAX faster than Rust in the general case? That is the wrong claim and it would be a bad one.

The better claim is narrower and more defensible: if you already have a Perl codebase, PAX is trying to buy you a better deployment and performance story without demanding a rewrite first.

That is a very different value proposition from "Perl now beats Rust." It is also the one real teams are more likely to care about.

There Is Also a Real Speed Story

PAX is not only about packaging. It also has a meaningful hot-path acceleration story.

One measured integer-loop example from the current tree used n = 400000000 and produced these results:

Mode Time
Stock Perl 12.15s
pax run compile-and-run pipeline 2.33s
PAX native artefact direct execution 0.08s

That is not the same thing as saying "all Perl becomes native instantly." It is saying something more defensible:

  • stock Perl pays normal interpreter cost
  • pax run pays compile plus execute cost
  • the generated native artefact shows what the compiled hot region can actually do

That is enough to move the project out of the "interesting idea" bucket and into the "real systems work" bucket.

If you want the practical follow-up on what changed next, read this:

PAX Update: One Binary, Real Applications and the Hard Parts of Compiling Perl

What Is Done and What Is Not

This part matters because overclaiming would damage the whole effort.

As of April 24, 2026, the current validation evidence includes:

  • perl -Ilib t/standalone_image.t -> 1..86
  • prove -lr t -> Files=18, Tests=332, Result: PASS

The project already has:

  • a standalone binary build pipeline
  • a paxfile.yml-driven build contract
  • compiled and hybrid code-unit packaging
  • packaged native artefact integration
  • embedded assets
  • standalone inspection and extraction tooling
  • native dispatch during standalone execution
  • a working webapp reference path
  • a two-stage Docker binary-only proof

What it does not yet have is universal, source-free compilation for arbitrary Perl application code with no compatibility floor at all.

That remaining gap still sits around:

  • framework-family compilation depth
  • complex top-level entrypoint lowering
  • unsupported hybrid residuals

So the honest reading is this: PAX already works as a real adaptive system, but it has not yet reached its final compiler frontier.

The Goal in One Line

If you compress the whole project down to one sentence, it is this:

Go-style deployment, Perl compatibility, native-speed hot paths.

That line is useful because it captures the actual ambition without pretending the hard parts are already solved.

Why Perl Developers Should Pay Attention Now

For years it was easy to dismiss compiled-Perl claims because the evidence never reached the level of real deployment.

PAX changes that because it is no longer only talking about:

  • loops
  • benchmark artefacts
  • partial compiler theory

It is talking about and demonstrating:

  • real standalone binaries
  • real assets
  • real framework integration
  • real Docker deployment paths
  • real native speedups on eligible code

If you care about Perl but have assumed its deployment and performance story was permanently stuck in an older era, this is the kind of project that deserves a closer look.

Not because it is finished.

Because it has moved beyond being hypothetical.

What Comes Next

The next phase is not more performance theater. It is deeper compiler coverage in reusable ways.

The project still needs:

  • broader framework-family compilation
  • less residual-source activation
  • stronger top-level entrypoint lowering
  • more reusable compiler and runtime improvements instead of one-off escapes

That is the right rule for a project like this. If one module family fails, the answer cannot keep being a one-time patch for one application. The compiler frontier has to move in a way that holds for the next app too.

Closing

PAX matters because it is aiming at the problem Perl developers actually have: how to keep the language, improve deployability and unlock more native-speed execution without pretending Perl's dynamic semantics are easy.

It is not done.

But "compile Perl into something deployable, fast and worth taking seriously" is no longer a joke or a nostalgia thread. It is a live engineering effort with enough real proof behind it to justify attention now.


← back to index