Kino: the web server for Ruby 4.0 that uses Ractors to run in parallel without forks
New Rack server combines a Rust front-end with parallel Ractors and promises to use all cores in a single process, but still runs into Rails.

A new Ruby web server called Kino hit the top of Hacker News proposing to solve an old problem in the language: how to use all CPU cores without paying the memory cost of the per-process fork model. The project, published on GitHub in the yaroslav/kino repository, requires Ruby 4.0+ and uses Ractors to actually run Ruby code in parallel within a single process.
The problem it tackles
Ruby's GVL (Global VM Lock) allows only one thread to execute Ruby code at a time. Because of this, servers like Puma in production fork one process per core, and each copy pays the memory cost of the entire app. Ractors, introduced as an experimental feature in Ruby 3.0 and reworked in Ruby 4.0 (with Ractor::Port, shareable_proc, and less lock contention), don't have this limitation: each Ractor has its own lock, so a single process can run Ruby in parallel.
According to the project's README, what was missing was a server that knew how to dispatch requests to these Ractors, and the changes in Ruby 4.0 made it feasible to build one.
How it works under the hood
The architecture is hybrid. A front-end written in Rust (using tokio + hyper) handles networking, while parallel Ractors run the Rack 3 application. There's also a fallback mode based on traditional threads for everything that doesn't run in a Ractor yet, including Rails.
There are three operating modes:
:ractor:workersRactors, each withthreadsthreads. Requires the app to beRactor.shareable?(frozen middleware, endpoints viashareable_proc). Forcing this mode with a non-shareable app raisesKino::UnshareableAppError.:threaded: the same machine, but with regular Threads. Runs any Rack app, including Rails, but serialized by the GVL for CPU work.:auto(default): uses:ractorwhen the app is shareable, otherwise it issues a warning and falls back to:threaded.
The project presents itself as "Puma-shaped": the same workers × threads topology, a familiar configuration DSL, and a kino CLI. The promise is that whoever knows how to run Puma knows how to run Kino.
The benchmark numbers
The tests were measured on an AWS c7a.2xlarge instance (8 AMD EPYC cores, 16 GB, Amazon Linux 2023), with Ruby 4.0.5 and YJIT. Puma ran with 8 workers × 3 threads; Kino ran in a single process. Requests were measured with wrk.
On light I/O endpoints, the README states that every Kino mode is 1.5x to 2.1x ahead of Puma's fork cluster. Some numbers from the main table (req/s):
/plaintext: Kino:ractor229,534 vs Puma 118,176/10k: Kino:ractor178,083 vs Puma 106,768/cpu (fib): Kino:ractor77,999 vs Puma 58,006 (a gain of +34%)
The standout is pure CPU: the Ractor mode runs CPU work more than 5x faster than Kino's own threaded mode (limited by the GVL), all within the same small process.
In terms of memory (measured by PSS), the synthetic benchmark app ran with ~7x less memory in Ractor mode: 148 MB for Kino versus 1,068 MB for the 8-worker Puma cluster.
The important caveat: Rails
Here's the point that Brazilian devs need to understand before getting excited. Rails isn't Ractor.shareable today, so Kino only serves it in the :threaded fallback mode, that is, a single process limited by the GVL. And the numbers look different:
- Kino
:threaded(one process): 2,637 req/s, 92 MB - Puma cluster (8 workers): 12,138 req/s, 389 MB
The README itself calls this an "honest trade-off": Puma's fork cluster uses all 8 cores and delivers ~4.6x more throughput, but at the cost of ~4x more memory. Rails in Ractor mode would close that throughput gap at the memory cost of a single process, but the blockers are upstream (in Ruby/Rails itself), tracked in doc/rails-on-ractors.md.
In other words: for most Rails applications in production in Brazil, there's no immediate gain today. The real appeal is for "pure" Rack apps (Sinatra, Roda, or custom services) that you can make Ractor-shareable.
The kino --check tool
An interesting practical detail: since figuring out why your app doesn't run in Ractor mode tends to be a nightmare (the infamous Ractor::IsolationError with no context), Kino ships with the kino --check command. It doesn't modify anything and lists every blocker: captured variables along with where they were defined, instance variables by path, and the class-level ivar trap. Example output:
$ kino --check
check: app is NOT Ractor-shareable
- app (Proc at app.rb:12)—captures `cache` = {} (Hash) (unshareable)
hints: freeze config at boot; build endpoints with Ractor.shareable_proc;
keep per-worker resources in Ractor.store_if_absent; or run mode :threaded.The exit status is 0/1, so it works in CI pipelines.
Production plumbing
The server isn't just a performance experiment. It includes graceful drain, crash supervision and respawn, bounded queues with 503 backpressure, request timeouts (that return 504 without killing the handler), protections against slowloris and stuck TLS handshakes, TLS via rustls, and an on_error hook to integrate with error trackers. There's also a read-only control plane (/stats, /metrics in Prometheus format, /ready and /live for Kubernetes probes) that keeps responding even when all Ruby workers are busy.
Installation doesn't require a Rust compiler in the released versions, which ship precompiled native gems for Linux (x86_64/aarch64, glibc and musl) and macOS arm64:
bundle add kino
bundle exec kino --init # generates a commented kino.rb
bundle exec kino # uses config.ru + kino.rb on port 9292What remains open
The README itself is explicit: Ractors are officially experimental in Ruby 4.0, and so is Kino. The threaded mode is described as solid, but the project positions itself as "the best way to experiment with Ractors today," not as a production replacement for Puma with Rails. With a roadmap that depends on changes in Ruby and Rails themselves, Kino is more a sign that the Ruby ecosystem is finally building tools on top of Ractors than an immediate server swap. It's worth following, especially for those maintaining CPU-bound Rack services who want to stop paying memory for forks.
Translated from the Brazilian Portuguese original · Read the original
Perplexity swaps DynamoDB for in-house database and cuts latency by 5x
The company behind the AI-powered search engine migrated its serving layer to CobbleDB, an internal database written in Rust, and cut batch read latency by up to 5x while saving at least 20% on storage.