AL+

Language: RO (română) EN (English)

Email us: paul@alplustech.com

A stable Ruby release can carry an experimental compiler

Evaluate Ruby's experimental ZJIT against your interpreter or YJIT setup using process lifetime, warmup, useful throughput and the actual memory budget.

Citiți articolul în română

A language release and a compiler inside it can have different maturity levels. Ruby 4.0 is a useful example: adopting the released runtime does not require treating ZJIT as a production default. The decision should turn on the application's constraints and the cost of learning about an experimental compiler. That leaves room for useful experimentation without presenting a version number as workload evidence.

Ruby 4.0.0 was released on 25 December 2025. Its announcement encourages ZJIT experimentation while suggesting holding off on production deployment. The earlier 18 December preview3 announcement establishes a preview, not an earlier stable release. This November 2026 retrospective preserves that distinction and does not turn plans for later compiler development into delivered improvements.

Separate runtime adoption from compiler selection

A team can have a good reason to upgrade Ruby while retaining its existing execution mode. Language compatibility, library requirements and maintenance can justify that work independently of a new compiler. Combining the decisions makes a regression harder to attribute: the application changed runtime and execution strategy together.

ZJIT also has concrete prerequisites. The release announcement specifies Rust 1.85.0 or newer to build Ruby with ZJIT support and the --zjit option to enable it. Build support and runtime activation are different conditions. The presence of a Ruby 4 executable does not establish that the supplied build includes the feature or that a worker actually enabled it.

Before evaluating performance, record the artifact and the effective startup configuration. This is a proposed evaluation practice, not a report of running Ruby here. It avoids an elementary ambiguity: an apparent comparison between two compilers might otherwise compare the same execution mode twice, or different application artifacts with unrelated changes.

Process lifetime changes the question

A command that exits soon after startup offers a different opportunity from a worker that stays alive for many requests. Compilation has to occur during some part of that lifetime. A useful evaluation should distinguish initial execution, the period in which behavior settles and the work completed after that period. An attractive later result does not erase an unacceptable first request.

Consider an illustrative scheduled report with a short execution window. Its owner cares about the entire run from process start to an accepted report. Excluding startup and warmup would remove part of the job being purchased. A persistent service may instead need both the behavior of newly started instances and the capacity of established workers, particularly when replacement happens frequently.

Neither example establishes a winner. Workload shape, supported operations and the time spent outside Ruby can limit the opportunity. A request dominated by another service cannot be assumed to gain the same benefit as a calculation performed in Ruby. Keep the user-visible completion criterion attached to the comparison.

Memory belongs beside throughput

The Ruby 4.0 ZJIT reference, consulted in November 2026, explains that generated machine code and compiler state add memory beyond the interpreter. This is versioned, maintained documentation rather than an immutable launch measurement. It supports including memory in an evaluation, not predicting a particular application's footprint.

For a memory-constrained worker, additional compiler state can compete with application objects and other processes. Compare useful completed work within the actual allowance. Increasing the allowance for one candidate changes the operating question and deserves explicit treatment. Otherwise the result may describe a larger machine rather than a more suitable execution mode.

Tail behavior also matters. A satisfactory average can coexist with slow requests, failed jobs or process replacement under pressure. Record those outcomes alongside throughput and peak memory. Define which regressions would reject the candidate before interpreting small differences. There is no universal threshold supplied by the existence of a new compiler.

Compare against the deployment you already understand

The relevant baseline may be the interpreter or YJIT. Keep application revision, inputs and external dependencies comparable, then identify the execution-mode change. Existing evidence about a stable YJIT deployment deserves weight. Replacing it merely to follow the newest compiler would discard familiar operating practice without establishing a compensating benefit.

The release's relative performance claims belong to the maintainers and their context. They are not AL+ measurements and do not predict throughput for a particular service. This article supplies no imported performance percentage, local benchmark or claim that ZJIT outperforms YJIT. Its proposed comparison asks a narrower question: whether the candidate meets this application's acceptance conditions.

A useful experiment budget includes investigation time and a stopping condition. If the candidate cannot execute the representative path correctly, collecting additional speed numbers is premature. If it behaves correctly but the benefit is too small to justify another operating mode, retaining the baseline is a complete outcome. Experimental work can produce knowledge without producing a rollout.

Compiler contributors can reasonably choose earlier exposure

The strongest counterargument is a team whose purpose includes improving the compiler. Finding unsupported patterns and reporting regressions can be worth temporary instability. That team evaluates learning and contribution as well as service performance. Its willingness to accept failures does not establish the same bargain for a customer-facing workload.

A bounded research environment may also tolerate failures that an operational service cannot. State who accepts that risk and where the experiment ends. Preserve the known artifact and configuration needed to return to the previous mode, and verify replacement workers use them. A setting edited in a file does not alter processes already running.

For custom software development, approve the runtime upgrade and compiler experiment as separate decisions. Choose interpreter, YJIT or an experimental ZJIT evaluation according to the work and the operating limits. Revisit that choice when evidence changes, with the original workload and acceptance conditions available for comparison.