Shopify Upgrades RubyGems Compact Index to Cut Install Times by 20 Percent

The RubyGems Compact Index: What Powers Every `bundle install` - Jenny Shen — Ruby on Rails

Ruby on Rails

Transitioning pre-compiled gems to single-ABI content-addressable storage slashes package size and speeds up bundle resolution by bypassing local C and Rust compilation.

AI-assisted summary of The RubyGems Compact Index: What Powers Every `bundle install` - Jenny Shen — original source. Check the original for full context.

Source published:

Key ideas

  • The RubyGems Compact Index handles over 50 million requests daily across three endpoints (/names, /versions, /info), serving metadata statically via CDN-backed S3 buckets with dynamic Rails servers operating as a fallback. (5:41)
  • RubyGems executed a zero-downtime blue-green S3 migration across 200,000+ gem info files to backfill created_at timestamps, enabling Bundler to enforce dependency cooldowns that mitigate account-takeover supply chain attacks. (12:27)
  • Because native C and Rust extension compilation accounts for over 70% of bundle install execution time, RubyGems 4.1 beta introduced single-ABI content-addressable gems to replace bloated multi-ABI fat gems, cutting sample bundle download sizes by 20%. (14:40)
  • Future compact index roadmap items include embedding vulnerability advisory metadata directly into dependency resolution and adding explicit Ruby engine requirements to prevent binary incompatibilities on runtimes like TruffleRuby. (22:27)

Detailed notes

## Background Published on YouTube by the Ruby on Rails channel on October 1, 2026, this Rails World talk features Shopify senior developer and RubyGems.org maintainer Jenny Shen. According to the show notes, Shen explains how the Compact Index powers every `bundle install` and highlights upcoming features like dependency cooldowns and content-addressable gems designed to make package resolution faster and safer.

## TL;DR The RubyGems Compact Index handles over 50 million daily requests across three endpoints (`/names`, `/versions`, and `/info`), compressing dependency metadata for over 200,000 gems into static S3 files that Bundler syncs via conditional HTTP requests and checksum comparisons. To defend against supply chain attacks, the RubyGems team executed a zero-downtime blue-green S3 migration to append publication timestamps (`created_at`) to every `/info` file, enabling native dependency cooldowns in Bundler. To address the fact that compiling C and Rust native extensions consumes over 70% of `bundle install` execution time, RubyGems 4.1 beta introduces single-ABI "content-addressable gems" suffixed with an eight-character checksum hash. This architecture replaces bloated multi-ABI "fat" gems, reduces bundle download sizes by 20% in fresh Rails benchmarks, and allows maintainers to publish binaries for new Ruby versions retroactively without breaking legacy Bundler clients.

## Atmosphere & style The talk begins with a playful, interactive energy as Shen warms up a hot afternoon conference crowd—in the final slot before the closing keynote—by performing an onstage card trick using a handmade magician's wallet. Her narrative style blends approachable, self-deprecating developer humor with clear architectural explanations that make low-level packaging infrastructure feel accessible and engaging. As the presentation progresses from foundational mechanics to supply chain security and ecosystem performance, the mood shifts into a focused, forward-looking engineering deep dive that leaves the audience energized about the future of Ruby tooling.

## Bulletin - [05:41](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=341s) The RubyGems Compact Index handles over 50 million requests daily across three endpoints (/names, /versions, /info), serving metadata statically via CDN-backed S3 buckets with dynamic Rails servers operating as a fallback. - [12:27](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=747s) RubyGems executed a zero-downtime blue-green S3 migration across 200,000+ gem info files to backfill created_at timestamps, enabling Bundler to enforce dependency cooldowns that mitigate account-takeover supply chain attacks. - [14:40](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=880s) Because native C and Rust extension compilation accounts for over 70% of bundle install execution time, RubyGems 4.1 beta introduced single-ABI content-addressable gems to replace bloated multi-ABI fat gems, cutting sample bundle download sizes by 20%. - [22:27](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1347s) Future compact index roadmap items include embedding vulnerability advisory metadata directly into dependency resolution and adding explicit Ruby engine requirements to prevent binary incompatibilities on runtimes like TruffleRuby.

## Key takeaways - [01:47](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=107s) The RubyGems Compact Index functions similarly to financial indexing and magic indexing wallets by compressing massive datasets (over 200,000 gems) into compact structures for rapid retrieval. - [05:41](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=341s) Bundler minimizes network transfer during dependency resolution by utilizing local caching in ~/.bundle/cache, ETag-driven byte-range diffs from /versions, and checksum comparisons before fetching /info files. - [08:55](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=535s) RubyGems offloads traffic by serving compact index files directly from AWS S3 via a CDN, falling back to dynamic Rails application servers only during cache misses or S3 downtime. - [08:55](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=535s) A monthly rake task compacts the continuously growing /versions file to consolidate duplicate delta lines from pushes and yanks back into single canonical summary rows. - [10:45](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=645s) Dependency cooldown periods establish a required time buffer (e.g., 7 days) before newly published gem versions can be resolved, allowing automated scanners and maintainers to identify hijacked accounts. - [12:27](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=747s) To support cooldowns without breaking production traffic, the RubyGems team used a blue-green migration to regenerate all 200,000+ S3 info files with publication timestamps in a parallel v2/ directory before switching CDN routing. - [14:40](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=880s) Compiling native C or Rust extensions consumes more than 70% of standard bundle install duration, making binary pre-compilation essential for package manager performance. - [16:35](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=995s) Legacy pre-compiled 'fat' gems must bundle binaries for multiple minor Ruby ABIs into a single package, leading to bloated downloads and requiring gem maintainers to write runtime binary selection code. - [16:35](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=995s) Multi-ABI packaging prevents gem authors from releasing binaries for newly launched Ruby versions on older gem releases without minting entirely new gem patch versions. - [18:02](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1082s) Content-addressable gems package binaries tailored to an individual Ruby ABI, using the first eight characters of the artifact checksum as a filename suffix while declaring the target platform as a dependency requirement. - [18:02](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1082s) To prevent legacy Bundler clients from misinterpreting 8-character SHA suffixes as unknown platform strings and crashing, content-addressable gems use required_rubygems_version metadata to remain invisible to older tools. - [22:27](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1347s) Integrating security advisories directly into the Compact Index would allow Bundler to surface vulnerability warnings in the terminal during bundle install before compromised code reaches production. - [22:27](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1347s) Adding Ruby engine metadata to the Compact Index will prevent non-CRuby runtimes like TruffleRuby from incorrectly downloading incompatible CRuby-compiled C extensions.

## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=0s) The Magic Trick: Revealing Rails 4

Jenny Shen kicks off the presentation as the final talk before the closing keynote at Rails World. Despite the scorching weather, she is thrilled to be onstage and begins by polling the room on who has heard of the RubyGems Compact Index. Seeing only a scattering of raised hands, she offers a warmup exercise in the form of a magic trick, inviting Michelle back onstage.

Jenny asks Michelle a simple question: "What is the first major Rails version you started developing on?" Michelle responds with "four." Jenny explains that this very number has traveled across the stage and is already waiting inside her pocket. She hands a card to Michelle, who opens it up to reveal the number four to gasps and laughter from the audience.

[01:47](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=107s) From Magic Wallets to the RubyGems Compact Index

Admitting that while real magicians never reveal their secrets, she is just a developer, Jenny discloses how the trick works: it relies on a "compact index." Specifically, it uses the Quiver Compact Index, a specialized magician's wallet designed to organize up to 16 cards for instantaneous indexing and sleight-of-hand retrieval. Because the wallet was sold out online, Jenny constructed her own handcrafted "V2" version.

She notes that "compact index" is also a term used in quantitative finance for an algorithm that condenses hundreds or thousands of index stocks down to a small, manageable basket while preserving diversification. Across magic, finance, and software, compact indexes share the exact same philosophy: "They compress and organize large amounts of information for quick retrieval or simplicity." In the Ruby world, the RubyGems Compact Index compresses dependency metadata across all 200,000+ gems hosted on RubyGems.org so that Bundler can resolve dependencies swiftly and reliably.

```mermaid flowchart TD accTitle: Core Concept of a Compact Index accDescr: Diagram illustrating how large datasets are compressed into an organized index across magic, finance, and RubyGems.

subgraph Inputs["Large Datasets"] Cards["Full Deck of Cards"] Stocks["100s–1000s of Index Stocks"] Gems["200,000+ Gems on RubyGems.org"] end

subgraph Compression["Compact Index Mechanism"] Wallet["Quiver Wallet (16 slots)"] Algo["Financial Compression Algorithm"] CI["RubyGems Compact Index"] end

subgraph Outputs["Fast Retrieval"] Trick["Instant Card Retrieval"] Portfolio["Diversified Mini-Portfolio"] Bundler["Fast Bundler Resolution"] end

Cards --> Wallet --> Trick Stocks --> Algo --> Portfolio Gems --> CI --> Bundler ```

[03:49](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=229s) Why RubyGems at Rails World & Speaker Intro

Jenny addresses why a RubyGems deep dive belongs at a Rails conference: Rails applications fundamentally depend on gems and seamless installation. Enhancing the performance, reliability, and security of gem resolution directly impacts every Rails engineer's day-to-day workflow, and the Compact Index sits at the center of all those recent architectural enhancements.

Introducing herself, Jenny jokes that while she is not a stage magician, she qualifies as a "software magician": "I can make code appear out of nowhere. The secret to that is AI. And I can sometimes make bugs magically appear as well." She works as a senior developer at Shopify based in Ottawa, Canada, and serves as a maintainer and operator of RubyGems.org, encouraging attendees to get involved and contribute to the platform.

[05:41](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=341s) Compact Index Architecture: Endpoints and Bundler Resolution

The RubyGems Compact Index is a high-throughput system handling over 50 million requests per day across three core endpoints: - `/names`: Returns the complete list of all gem names on the platform. - `/versions`: Returns each gem name alongside all available version numbers and their corresponding info checksums. - `/info`: Returns detailed version-by-version dependency trees, Ruby/RubyGems requirements, and gem checksums for an individual gem.

Bundler relies primarily on the `/versions` and `/info` endpoints during resolution. When a user runs `bundle install` without an existing `Gemfile.lock`, modifies dependencies in `Gemfile`, or lacks local gems, Bundler contacts `/versions`. Bundler caches index files locally inside the `~/.bundle/cache` directory and performs conditional HTTP requests using `ETag` headers. When changes exist upstream, the server responds with only the appended byte range of new versions, which Bundler seamlessly merges into its local copy.

To evaluate individual gem compatibility and transitive dependencies, Bundler queries the `/info` endpoint. Each row in an info response details a version, its platform requirements, dependency constraints, and cryptographic checksums. Bundler saves these info responses locally. Before requesting an update for a gem's `/info` file, Bundler computes a local hash of the file's contents and compares it to the `info_checksum` listed in the `/versions` file; only if the checksum differs does Bundler download an updated info payload.

```mermaid flowchart LR accTitle: Bundler and Compact Index Interaction accDescr: Resolution workflow showing Bundler synchronizing the versions and info endpoints.

subgraph Client["Local Machine"] BI["bundle install"] BCache["Local Bundle Cache (~/.bundle/cache)"] end

subgraph Endpoints["RubyGems Compact Index"] V["/versions Endpoint"] I["/info/:gem Endpoint"] end

BI -->|"1. Conditional Request with ETag"| V V -->|"2. New version diff bytes"| BCache BCache -->|"3. Compare SHA against info_checksum"| BCache BCache -->|"4. Fetch if hash differs"| I I -->|"5. Dependencies & Requirements"| BI ```

[08:55](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=535s) Under the Hood: Pushes, Yanks, S3 Caching, and Maintenance

Jenny outlines the backend architecture handling gem lifecycle events on RubyGems.org. Whenever an author pushes a new gem release, RubyGems enqueues background jobs that append a new line to the `/versions` file and update the gem's corresponding `/info` file. Both artifacts are written directly to an AWS S3 bucket.

The edge architecture is designed to offload traffic from web workers: - Inbound requests through the CDN targeting the Compact Index are routed straight to static assets in the S3 bucket. - If a file is absent from the bucket or an S3 outage occurs, the CDN fails over to dynamic Rails application servers. - When a version is yanked, the system subtracts that version from `/versions` and strips it out of the `/info` document.

Because high volumes of pushes and yanks append delta lines over time, the `/versions` file naturally expands in size. To keep client payloads small and parsing fast, RubyGems executes a monthly rake task that compacts and consolidates duplicate lines for every gem down to a single canonical summary row.

[10:45](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=645s) Security Evolution: Dependency Cooldowns

Jenny transitions to major recent upgrades, starting with supply chain defense via dependency cooldowns. A cooldown establishes a time delay—such as 7 days—before newly published gem versions can be resolved and installed by clients. If a new Rails release ships today under a 7-day cooldown policy, Bundler will intentionally ignore it until the 7-day window elapses.

The feature directly counters a surge in account takeover attacks against open-source maintainers, a threat amplified by AI-driven automation and phishing campaigns. Jenny highlights the high-profile Axios compromise on npm earlier in the year, where a hijacked maintainer account published a malicious package version. Cooldown windows give automated security scanners and maintainers vital breathing room to discover compromised releases and yank them before production applications run automated updates. Following similar initiatives across PyPI and npm, the Ruby community recognized the urgency to incorporate cooldown capabilities natively.

[12:27](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=747s) The Blue-Green S3 Migration and Bundler Support

Enabling cooldowns requires Bundler to verify the exact publication timestamp of every gem version. Historically, the Compact Index `/info` format had no publication dates. Fortunately, the extensible Compact Index specification permits optional entries in the requirements section of the format, making it possible to append a `created_at` timestamp.

However, rolling out this change posed a massive data infrastructure challenge: every single one of the 200,000+ info files hosted in S3 had to be regenerated and replaced without interrupting millions of daily production requests. The team opted for a blue-green migration: 1. The CDN continued serving active live traffic from the existing primary directory (the "blue" index). 2. Code changes were deployed so that all incoming gem pushes and yanks updated both the active index and a new `v2/` directory in parallel. 3. A background migration backfilled updated `/info` files containing `created_at` metadata for all 200,000 gems into the `v2/` prefix. 4. Once validation completed, the CDN was shifted to point directly to the `v2/` directory, retaining the ability to instantly roll back if regressions occurred.

With publication timestamps fully integrated into the upstream Compact Index, core maintainer Hiroshi Shibata (hsbt) added dependency cooldown support directly to Bundler. Developers can leverage this protection using the `--cooldown` CLI flag during gem installation, or enforce it globally via Bundler configuration and Gemfile settings.

- Cooldown settings can be declared directly in the `Gemfile`, via Bundler configuration, or passed as an argument to `gem install`. - The blue-green approach prevented any CDN downtime across the 200,000 regenerated files while preserving immediate rollback capabilities.

[14:40](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=880s) The Cost of Native Extensions and Legacy Pre-Compilation

Turning the focus from dependency cooldowns to raw speed, Jenny Shen highlights that the Ruby ecosystem must remain competitive, particularly with tools like Python’s `uv` demonstrating how fast modern package management can be. Profiling reveals that more than 70% of total `bundle install` execution time is consumed by compiling native extensions—a figure Shen notes with a laugh is "a lot." Native extensions allow gem authors to write performance-critical components in C or Rust. When these gems lack pre-compiled binaries, Bundler must execute compilation scripts declared in the gem’s gemspec on the developer’s local machine before the gem can be used.

```mermaid flowchart TD accTitle: Evolution of Pre-compiled Gems in RubyGems accDescr: Comparison between legacy multi-ABI fat gems and the new single-ABI content-addressable gems.

subgraph Legacy["Legacy Pre-compiled Gems (Multi-ABI)"] L1["Platform-suffixed Gem<br/>(e.g., nokogiri-x86_64-linux)"] L1 --> L2["Bundles Ruby 3.1 ABI"] L1 --> L3["Bundles Ruby 3.2 ABI"] L1 --> L4["Bundles Ruby 3.3 ABI"] L1 --> L5["Requires runtime binary selection logic"] end

subgraph CAG["Content-Addressable Gems (Single-ABI)"] C1["SHA-suffixed Gem<br/>(First 8 hex digits)"] C1 --> C2["Targeted Single Ruby ABI"] C1 --> C3["Platform moved to metadata requirement"] C1 --> C4["New ABIs publishable after gem release"] end ```

The established workaround in the Ruby community has been publishing pre-compiled "fat" binaries, exemplified by gems like Nokogiri. Rather than building from source, users download binaries already compiled for their specific operating system and architecture. However, native binaries depend on Ruby's Application Binary Interface (ABI). Because minor Ruby releases alter internal C data structures and engine mechanics, compiled binaries are not compatible across different Ruby versions. To make pre-compilation practical, maintainers historically bundled binaries for every supported minor Ruby version into a single platform-specific gem package.

- Compiling native extensions written in C or Rust accounts for over 70% of standard `bundle install` wall-clock time. - Minor Ruby releases introduce ABI breaking changes, requiring separate binary builds for each supported Ruby ABI. - Existing pre-compiled gems package multiple ABI variants into one fat gem per target operating system architecture.

---

[16:35](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=995s) The Limitations of "Fat" Multi-ABI Gems

While shipping pre-compiled gems provides a substantial speedup over local compilation, the legacy multi-ABI paradigm creates several architectural headaches:

First, fat gems are unnecessarily bloated. Because a single package bundles binary artifacts for multiple Ruby ABIs, developers download megabytes of compiled code for Ruby versions they do not run, even though "most of the time, you'll only need to use one." Second, gem maintainers must write runtime loader scripts inside their gems to inspect the running Ruby version and dynamically require the matching native artifact.

Crucially, the legacy design locks maintainers out of updating existing releases. If a maintainer releases a gem supporting Ruby 3.2 and 3.3, and Ruby 3.4 is subsequently released, the maintainer cannot retroactively attach a Ruby 3.4 ABI binary to that existing gem release without creating an entirely new patch version. Being able to independently distribute distinct, single-ABI binaries would drastically reduce gem tarball sizes, speed up downloads, simplify gem codebases, and allow post-release publishing of new ABI targets for older gem versions.

---

[18:02](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1082s) Content-Addressable Gems and Compact Index Adjustments

To resolve the constraints of multi-ABI packaging, the RubyGems team implemented "content-addressable gems," a concept originally envisioned by Aaron Patterson. Instead of packaging multiple ABIs under a platform suffix, content-addressable gems package pre-compiled artifacts scoped to a single, specific Ruby ABI.

Because RubyGems and the compact index historically rely on unique tuple keys that prevent publishing multiple gem variations for the same platform and version string without collisions, a structural naming and metadata adjustment was required:

1. **SHA Suffixing:** The gem name's platform suffix is replaced with the first eight characters of the artifact's checksum hash. 2. **Platform as a Requirement:** The target platform (e.g., `x86_64-linux`, `arm64-darwin`) is moved out of the filename suffix and into the compact index’s dependency requirements list. 3. **Ruby ABI Scoping:** The `required_ruby_version` specification is constrained directly to the single exact Ruby ABI for that binary.

This architectural shift introduced a major backwards-compatibility hurdle: older versions of Bundler parse any suffix on a gem name as a platform identifier, causing legacy clients to misinterpret the eight-digit checksum as an unknown platform and crash. To safeguard older installations, the team added a `required_rubygems_version` constraint to the metadata. This effectively hides content-addressable gems from legacy Bundler clients while serving them cleanly to modern ones.

- The feature made its debut in the RubyGems 4.1 beta release. - Work is underway across the broader ecosystem toolchain, including a pull request to `rake-compiler` so maintainers can build and publish single-ABI content-addressable gems directly from standard build pipelines. - Maintainers who have not yet automated pre-compilation can adopt `ci-build-gem`, a utility created by Edward Loveall that generates GitHub Actions workflows to compile binaries per platform and upload them to RubyGems.org. - When resolving dependencies, modern Bundler clients prioritize content-addressable gems over legacy multi-ABI variants, rendering resolved entries in a dedicated section of `Gemfile.lock`. - In test benchmarks deploying single-ABI versions of all pre-compiled gems for a fresh Rails application, overall bundle download size shrank by 20%, laying the infrastructure needed to pre-compile the dozens of native gems that currently compile from source.

---

[22:27](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1347s) Future Compact Index Horizons: Advisories and Engine Targeting

Looking beyond cooldowns and content-addressable packages, Shen outlines upcoming improvements under consideration for RubyGems and the compact index format:

```mermaid flowchart LR accTitle: Proposed Compact Index Metadata Additions accDescr: Future extensions to compact index metadata including security advisories and Ruby engine information.

subgraph CI["Compact Index Entry"] A["Gem Name & Version"] B["Existing Dependency Requirements"] end

subgraph Proposals["Proposed Additions"] C["Security Advisory Data<br/>(Warn on known vulnerabilities)"] D["Ruby Engine Requirement<br/>(Differentiate CRuby vs. TruffleRuby)"] end

CI --> C CI --> D ```

One major area is native security warnings during installation. Building on the safety benefits introduced by cooldown periods, the compact index could embed vulnerability advisory metadata. This would enable Bundler to immediately detect and flag vulnerable gem versions directly during `bundle install`, alerting developers before insecure code hits production environments.

Another area is expanding runtime compatibility requirements within pre-compiled metadata. Currently, the compact index lacks explicit Ruby engine information. This omission causes bugs when alternative runtimes such as TruffleRuby attempt to install gems: TruffleRuby can inadvertently fetch CRuby-compiled C extensions that fail to link properly. Injecting engine metadata directly into the compact index will enable gem authors to compile and distribute separate native binaries for non-CRuby engines while ensuring package resolution tools always download the correct binary for the active runtime.

---

[23:50](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=1430s) Conclusion and Community Roadmap

Shen concludes by reviewing the mechanics of the compact index, its interaction with Bundler, and recent features like dependency cooldowns and content-addressable pre-compilations. She encourages attendees to test the beta releases of RubyGems and Bundler, noting that developer feedback during beta cycles is vital for uncovering edge cases before stable distribution. Detailed release notes are available on the RubyGems release pages, and a forthcoming technical blog post will document the inner workings of content-addressable gems. Expressing gratitude to the RubyGems contributors and the Shopify engineering team, Shen wraps up the presentation to audience applause.

## Notable quotes > [00:00](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=0s) What is the first major Rails version you started developing on? — Jenny Shen

> [01:47](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=107s) They compress and organize large amounts of information for quick retrieval or simplicity. — Jenny Shen

> [03:49](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=229s) I can make code appear out of nowhere. The secret to that is AI. And I can sometimes make bugs magically appear as well. — Jenny Shen

> [16:35](https://www.youtube.com/watch?v=Z9XUvK8Sr5c&t=995s) most of the time, you'll only need to use one. — Jenny Shen

## Mentioned Jenny Shen, Michelle, Hiroshi Shibata (hsbt), Aaron Patterson, Edward Loveall, Shopify, Ruby on Rails, Rails World, RubyGems, RubyGems.org, RubyGems Compact Index, Bundler, Quiver Compact Index, AWS S3, Axios, npm, PyPI, uv, Nokogiri, rake-compiler, ci-build-gem, GitHub Actions, CRuby, TruffleRuby

## Video description Dependency cooldowns and content-addressable gems are coming to RubyGems. Jenny Shen (Shopify) explains how the compact index behind every 'bundle install' works, and what's changing to make it safer and faster.

Thank you Shopify for sponsoring the editing and post-production of these videos. Check out insights from the Engineering team at: https://shopify.engineering/

#RailsWorld #rubygems

[Source](https://www.youtube.com/watch?v=Z9XUvK8Sr5c)

中文简报

Shopify 升级 RubyGems Compact Index,安装时间缩短 20% 将预编译 gem 转向单 ABI 内容寻址存储,通过跳过本地 C 和 Rust 编译大幅缩减包体积并加快 bundle 解析速度。 RubyGems Compact Index 每天通过三个端点(`/names`、`/versions` 和 `/info`)处理超过 5000 万次请求,将 20 多万个 gem 的依赖元数据压缩为静态 S3 文件,Bundler 则通过条件 HTTP 请求与校验和比对完成同步。为防御供应链攻击,RubyGems 团队执行了零停机蓝绿 S3 迁移,向每个 `/info` 文件追加发布时间戳(`created_at`),从而在 Bundler 中启用原生依赖冷却机制。针对编译 C 和 Rust 原生扩展消耗超过 70% 的 `bundle install` 执行时间这一问题,RubyGems 4.1 beta 引入了带有 8 位校验和哈希后缀的单 ABI“内容寻址 gem”。该架构取代了臃肿的多 ABI“fat gem”,在全新的 Rails 基准测试中将 bundle 下载体积减少了 20%,并允许维护者在不破坏旧版 Bundler 客户端的前提下追溯性地为新 Ruby 版本发布二进制文件。 RubyGems Compact Index 每天通过三个端点(/names、/versions、/info)处理超过 5000 万次请求,通过 CDN 支持的 S3 存储桶以静态方式提供元数据,并以动态 Rails 服务器作为后备方案。 (5:41) RubyGems 在 20 多万个 gem info 文件中执行了零停机蓝绿 S3 迁移以回填 created_at 时间戳,使 Bundler 能够执行依赖冷却,从而缓解账户接管类的供应链攻击。 (12:27) 由于原生 C 和 Rust 扩展编译占用了超过 70% 的 bundle install 执行时间,RubyGems 4.1 beta 引入了单 ABI 内容寻址 gem 来取代臃肿的多 ABI fat gem,使样本 bundle 下载体积缩减了 20%。 (14:40) Compact Index 未来的路线图规划包括直接将漏洞通告元数据嵌入依赖解析中,以及添加显式 Ruby 引擎要求,以防止在 TruffleRuby 等运行时上出现二进制不兼容。 (22:27)

Reading summary

RubyGems.org maintainer Jenny Shen explains that recent architectural overhauls to the RubyGems Compact Index improve dependency resolution performance and software supply chain security across the Ruby ecosystem. Architecture and Bundler Resolution Workflow (5:41) The RubyGems Compact Index serves over 50 million requests daily across three primary endpoints: `/names`, `/versions`, and `/info`. Bundler caches index files locally under `~/.bundle/cache` and makes conditional HTTP requests with ETag headers against `/versions` to download only appended byte ranges. To resolve individual dependencies, Bundler checks the local hash of each gem's `/info` cache against the `info_checksum` reported in `/versions`, downloading detailed dependency and checksum rows only when values diverge. At the storage layer, gem publishing and yanking trigger background jobs that update `/versions` and `/info` assets directly inside an AWS S3 bucket. Incoming requests pass through a CDN pointed at static S3 files, failing over to dynamic Rails application servers during S3 outages or cache misses. Because continuous pushes and yanks cause delta records to accumulate in `/versions`, RubyGems runs a monthly maintenance task to compact duplicate rows into single canonical entries. Dependency Cooldowns via Blue-Green S3 Migration (10:45) To counter automated account takeover attacks against open-source maintainers—such as the compromise seen on npm's Axios package—the team added dependency cooldown capabilities. A cooldown rule delays the installation of newly published versions by a set window, such as 7 days, giving maintainers and security scanners time to detect and yank malicious releases before automated CI pipelines pull them in. Supporting this feature in Bundler required adding a `created_at` timestamp to the requirements section of every `/info` record. To rewrite all 200,000+ files without CDN disruption, the team implemented a blue-green migration: live traffic remained on the primary directory while incoming pushes updated both paths, background tasks backfilled the new `v2/` directory, and CDN routing shifted over once data integrity was verified. Hiroshi Shibata subsequently added cooldown configuration to Bundler via CLI flags, global settings, and Gemfile declarations. Content-Addressable Pre-Compiled Gems (14:40) Compiling C or Rust native extensions on developer machines accounts for over 70% of standard `bundle install` wall-clock time. Historically, gem authors mitigated this by shipping pre-compiled 'fat' gems that bundled multiple Ruby Application Binary Interface (ABI) targets into a single platform package. Shen notes this approach creates bloated download archives, requires maintainers to write runtime binary selection scripts, and prevents adding newer Ruby ABI builds to existing gem releases without cutting an entirely new patch version. To resolve these constraints, RubyGems implemented single-ABI content-addressable gems. This architecture replaces the gem name's platform suffix with the first eight hex digits of the file's checksum, shifts target platform specifications into compact index requirements, and pins `required_ruby_version` directly to the specific ABI. To prevent older Bundler clients from misidentifying checksum suffixes as platforms and crashing, these gems require modern RubyGems versions. In initial benchmarks on a fresh Rails application, single-ABI packaging decreased total bundle download size by 20%. Future Compact Index Metadata Extensions (22:27) Looking ahead, Shen describes two metadata enhancements planned for the Compact Index specification. The first proposes injecting security advisory data directly into the index, allowing Bundler to detect known vulnerabilities during installation and warn developers before compromised code is deployed. The second proposal involves adding explicit Ruby engine requirements. Because the Compact Index currently omits engine identifiers, alternative runtimes like TruffleRuby can inadvertently fetch native C extensions compiled specifically for CRuby, resulting in dynamic linking errors. Adding engine metadata would allow authors to publish dedicated binary builds for non-CRuby engines and ensure resolvers select matching artifacts. Shen encourages developers to test the RubyGems 4.1 beta releases to uncover edge cases in content-addressable gem resolution, noting that broader tooling integration—including updates to `rake-compiler` and Edward Loveall's `ci-build-gem`—is underway to make single-ABI compilation standard across the community.

Source quotes

[0:00] Jenny Shen: What is the first major Rails version you started developing on? [1:47] Jenny Shen: They compress and organize large amounts of information for quick retrieval or simplicity. [3:49] Jenny Shen: I can make code appear out of nowhere. The secret to that is AI. And I can sometimes make bugs magically appear as well. [16:35] Jenny Shen: most of the time, you'll only need to use one.

Original transcript

[0:00] Awesome. [0:06] [music] [0:11] Um, thanks Michelle. Oh. Um, hey [0:14] everyone. Thanks for coming, especially [0:17] since this is the last talk before the [0:20] ending keynote. Been I have a great time [0:23] at Rails World so far. Even though the [0:26] weather is so hot, uh it's amazing to uh [0:30] it's amazing to uh hang out with cool [0:34] folks like y'all. [0:36] Today I'll be talking about the Ruby [0:38] Gems Compact Index. And um to get us [0:42] started, who has heard of the Compact [0:44] Index before? Raise your hands. Oh, [0:47] looks like there's a couple of you. So, [0:50] for those who don't know, uh, and get us [0:53] warmed up a bit, uh, I have a simple [0:55] magic trick, uh, for this. Uh, I'll get [1:00] Michelle to get back up here. Well, [1:02] let's have a round of applause for [1:04] Michelle. [1:06] [applause] [1:09] >> Amazing. Simple question for you. [1:12] >> Okay. [1:12] >> Uh, what is the first major Rails [1:15] version you started developing on? Um, [1:20] four. [1:21] >> Okay. [1:21] >> Yeah. [1:22] >> Well, that number has traveled a meter [1:26] and h is in my pocket right here. Would [1:31] you mind opening? [1:34] >> Okay. [1:34] >> And seeing [laughter] what it is. [1:38] >> It's a four. [1:39] >> Whoa. [1:41] Amazing. Okay, I'll get [laughter] that [1:43] back. Thanks, Michelle. [1:47] So, a magician never spoils their [1:52] secrets, but I'm not really a magician, [1:55] so I'll share the secret to this trick. [1:57] It's the compact index. More [2:00] specifically, it's the quiver compact [2:03] index. [2:04] Um, it is a wallet that stores up to 16 [2:09] cards and allows you to quickly uh take [2:12] them take them out. Um, unfortunately it [2:16] was all sold out online, [2:19] so I made my own right here. I think [2:24] it's definitely an upgrade. It's V2. So [2:28] yeah, that is [laughter] [2:30] the V2 version. Um, but the compact [2:35] index is actually also a algorithm. [2:40] Uh, it's related to finance. It [2:42] compresses 100 to thousands of stocks [2:46] within an index and it compresses it [2:49] down to uh only a handful while [2:52] maintaining diversification. [2:55] Um [2:57] I'm not supposed to this isn't the [3:01] compact index I'm supposed to be talking [3:03] about though. It's the Ruby gems compact [3:05] index but we um but they all share a [3:10] similar theme. They compress and [3:12] organize large amounts of information [3:15] for quick retrieval or simplicity. [3:18] So for the quiver compact index [3:21] compresses a deck of cards into an [3:23] organized wallet while for the financial [3:26] al algorithm it compresses hundreds of [3:29] stocks into a tiny fraction while [3:31] maintaining diversification. [3:34] And the Ruby gems compact index is not [3:38] that different. It compresses info from [3:41] all 200,000 gems on rubyjams.org for [3:44] bundler to resolve uh dependencies. [3:49] Ruby gems is important uh for the Ruby [3:53] and Rails ecosystem. You might be [3:56] thinking why are we talking about Ruby [3:58] gems at Rails World? It's supposed to be [4:00] a Rails conference. Well, gems and gem [4:03] installation is an important part in [4:06] running a Rails application. [4:08] um and in um and it's important to keep [4:12] it up to date by improving things like [4:15] performance, reliability, and security. [4:20] And when we made these improvements, we [4:23] found that the compact index is a core [4:27] part of making these changes. So today, [4:30] we'll be talking a little bit about the [4:32] internals of the compact index and how [4:35] it interacts with bundler. recent [4:38] evolutions uh to the compact index and [4:42] the new features in bundler and some [4:45] future additions that we can make. [4:47] Hopefully out of this talk you can use [4:49] some of these new features to level up [4:51] your dependency installation game. But [4:55] before we get started, let me introduce [4:57] myself. I'm Jenny. Um I am not a [5:01] magician, but I can be considered a [5:04] software magician. Um, I can make code [5:07] out appear out of nowhere. Um, the [5:10] secret to that is AI. Um, and I can [5:15] sometimes uh make bugs magically appear [5:18] as well. Uh, I work at Shopify as a [5:22] senior developer and I'm in based in [5:25] Ottawa, Canada. I'm also a rubygeems.org [5:29] maintainer [5:31] and operator. uh we always welcome [5:34] contributions to the project. So if you [5:36] find some of the stuff interesting, come [5:39] find me afterwards. [5:41] Okay. So let's talk a bit about the Ruby [5:43] gems compact index. As I mentioned [5:46] before, um it's it compresses [5:51] information from more than 200,000 gems [5:53] on rubygeems.org for bundler to use. It [5:57] runs with three endpoints and uh serves [6:00] over 50 million requests per day. These [6:04] three endpoints are the info endpoint, [6:07] the versions endpoint, and the names [6:09] endpoint. The bundler only uses the [6:12] former two. [6:14] when you bundle install [6:17] if uh there's no gem file lock uh [6:21] there's changes to the gem file and [6:24] there's depend or if there's uh [6:27] dependencies not found locally um [6:30] bundler will need to uh re-resolve and [6:33] interact with the index first of which [6:36] it'll make sure there's a up-to-date [6:38] list of gems and this is the versions [6:41] endpoint so as you can see here this is [6:44] in this is what it looks like. So this [6:48] all the list of gems available to [6:50] download. Uh you can see the name of the [6:53] gem, the versions available and [6:55] something called the info check sum that [6:57] we'll get back to later. Uh the index is [7:01] also stored locally on your machine and [7:04] we try and bundler tries to keep them in [7:07] sync uh and it's stored in the bundle [7:10] cache uh directory in your machine. So [7:15] uh bundler will try and update the uh [7:19] versions file locally if it needs to be [7:21] updated. So it will request with an e [7:25] tag and re the index will return any [7:29] bytes that uh are new or new uh versions [7:33] and updated here. So um the jam called d [7:38] gets updated locally. [7:42] Then bundler needs to resolve more needs [7:45] more info about each gem in order to [7:47] resolve or determine if it can be [7:50] installed. Some of this includes like [7:53] the transited dependencies and their [7:55] requirements uh Ruby or Ruby gems [7:58] requirements and the gem check sum. If [8:02] you have gem check sum stored in your [8:04] lock file and needs to compare compare [8:08] um this is exactly what the info routes [8:11] does. [8:12] Uh this is an example. It gives the [8:15] versions uh the version for each row the [8:19] dependencies and also the requirements [8:22] like the check sum for it's also stored [8:26] locally and to determine if it needs to [8:30] be updated uh bundler will calculate a [8:35] hash um of the contents of the file and [8:39] if it matches the info check sum we [8:41] mentioned earlier uh then it doesn't [8:44] need a ref but if the versions check sum [8:48] is different uh it'll request the new uh [8:52] info file. Something else that I want to [8:55] talk about is what happens when a new [8:57] version gets pushed. So um Ruby gems [9:02] when a gem gets pushed the um will fire [9:07] a background job to update the versions [9:09] file and it'll do the same for the gem [9:14] info file and it gets updated to an AWS [9:17] bucket. Uh you may be asking why do are [9:22] we updating to AWS bucket? Well, uh, for [9:25] our CDN, it checks if a request comes in [9:29] and if it's a compact index request, [9:32] it'll update, uh, it'll redirect to the, [9:36] uh, AWS bucket and serve it through [9:38] there. And if not, it'll fall back to [9:42] the server if the file doesn't exist or [9:46] uh, the bucket uh, there's something [9:48] wrong with the bucket. [9:51] So when a gem gets pushed uh the a um [9:58] the new row the new gem gets appended to [10:02] a new line in the versions file and it [10:05] gets updated in the info file and when a [10:08] gem gets yanked it'll subtract that [10:10] version and will remove it from the info [10:13] file. You may be thinking, "Oh, if [10:16] there's a lot of pushes and yanks, [10:18] wouldn't the versions file get really [10:21] large?" Well, we have a monthly rake [10:25] task that uh consolidates [10:28] um all of the [10:31] redundant lines of a gem and rolls it up [10:35] to one line here. So, yeah, uh that's a [10:40] little bit about the index and how [10:42] Bundler interacts with it. Now we can [10:45] talk about some of the exciting new [10:47] changes we have to the index. The first [10:50] one is related to security. Uh this is [10:55] dependency cooldowns more specifically [10:57] dependency cooldowns. So um [11:02] if you a cool down if you specify a cool [11:05] down of something like seven days then [11:08] new versions of the gems only get [11:10] installed seven days after publish. So [11:13] if uh a new Rails version comes out [11:17] today uh you will need to wait uh after [11:21] 7 days it will be able to be installed. [11:24] You may be asking why do we need this [11:28] feature? Well, [11:31] over the recent while, there has been an [11:34] increase of gem takeover attacks. [11:38] Um, [11:39] more so because of AI uh being able to [11:43] take over uh maintainers accounts and [11:46] push push malicious versions. So, the [11:50] one that inspired it all is earlier this [11:53] year in the MPM ecosystem, Axios was [11:56] compromised. So someone was able to take [11:59] over the maintainer's account and push a [12:02] malicious version and then um and [12:05] cooldowns allow time to detect malicious [12:08] gems before installation. So scanners [12:11] will able be able to detect them and [12:13] then yank them. Pippi and npm uh were uh [12:19] quickly added cooldowns to their tooling [12:23] and Ruby gem should follow suit. How do [12:27] we do that you may ask? Uh Bundler would [12:32] need to know uh publish timestamps of [12:36] the gems. But as you can see here, [12:39] there's no [12:41] timestamps or create info in the info in [12:45] the info info file. Luckily enough, uh [12:49] in the compact index spec, you can add [12:52] more requirements uh in the requirements [12:55] section. So we can easily just add the [12:57] create at information here. [13:00] What makes this difficult though is as I [13:02] said before all of the files are stored [13:05] in in a WS bucket. So we had to [13:08] regenerate 200,000 [13:11] files uh for each gem for each info file [13:15] uh in order for this to work. uh we [13:19] investigated different approaches but we [13:21] landed on something called the blue [13:24] green migration. So essentially what we [13:27] did is that we have the CDN pointing to [13:30] the current index and then for new [13:33] pushes and yanks we update the current [13:35] index and uh the new one under a V2 [13:39] subdirectory and then we backfill [13:42] 200,000 gems uh the in info files of [13:46] them into the new directory. [13:50] Then once that was completed, we were [13:52] able to uh switch um direct the CDN to [13:56] serve the new directory. And this was [14:00] all possible. Um well, we chose this [14:03] approach because if something did go [14:05] wrong, we could easily revert back and [14:08] uh go to the pre-existing [14:11] version. [14:13] So now there is create at info in the [14:16] compact index and HSBT added the feature [14:20] uh cooldown feature in bundler. Uh you [14:24] can add the cooldown flag to um your gem [14:29] install methods. You can set it in your [14:32] uh configuration and in your gem file. [14:36] Um, you can also read more in uh this [14:40] blog post right here. Cool. So, that's [14:44] cool downs. Next, I want to talk about [14:47] performance. Um, [14:51] UV is super fast and in order for um [14:56] Ruby gems to uh stay up to date, we want [15:01] it to be fast as well. Uh we found that [15:05] as more than 70% of bundle install times [15:08] is compiling native extensions [15:12] which [snorts] is a lot. Um and uh you [15:16] may ask what are native extensions? Well [15:20] some gems have C or R code uh to make [15:24] the gem more performant and they need to [15:27] compile before use. So when you bundle [15:31] install uh bundler will run uh a [15:37] compilation script specified in the gem [15:39] spec right here. [15:41] There is a pre-existing solution to this [15:44] though which is having the gem [15:46] pre-ompiled for you. Uh an example of [15:49] this is no giri. So you can see there's [15:52] multiple versions compiled by platform [15:55] and within each platform uh there are [15:59] many [16:00] versions um AI versions for each uh gem. [16:07] An AI version is an application binary [16:10] interface. So what that means is that [16:13] with each um minor Ruby version there [16:18] are data structures and internals that [16:20] changes and when you when so binaries [16:24] aren't compatible between uh each Ruby [16:29] version. So um you need to have one [16:32] compile for each one. [16:35] So um yeah the more pre-ompiled gems the [16:40] faster but there's one problem uh or one [16:44] thing that is suboptimal a pre-ompiled [16:46] gem can be big uh as I mentioned before [16:50] um a pre-ompiled gem supports oh oops [16:54] multiple [16:57] multiple AIs [16:59] um [17:01] multiple AIS and but most of the time, [17:04] you'll only need to use one uh because [17:08] uh yeah, you'll probably use one Ruby [17:10] version. Also, [17:13] um gem maintainers need to add code in [17:18] their gem to load the right binary um in [17:22] as well. So being a being able to uh [17:26] publish gems per for one AI allows for [17:31] smaller gems, faster downloads, and less [17:34] configuration for maintainers. [17:37] Another perk is that for existing gems, [17:41] uh, [17:43] you can't when a new re ruby version [17:46] comes out, you can't update the gem with [17:49] new Ruby ABI versions. And it'll be [17:53] great to be able to push new um, Ruby [17:58] API support afterwards. [18:02] And we added that that exact ability. [18:05] This is coined as content addressable [18:08] gems. This is this concept was [18:12] originally proposed by Aaron Patterson. [18:16] Uh and it basically is a pre-ompiled jam [18:19] scope by Ruby AI. Um as you can as [18:24] before oh as before um the the gem is [18:30] platform suffix and is multi-ABI and now [18:34] is Shaw suffix with the single AI. Um [18:39] the reason why we had to make this [18:40] naming change is that the [18:44] currently we cannot specify multiple [18:47] APIs per version because that will cause [18:51] a name collision. So what does that mean [18:54] for a compact for the compact index? It [18:57] means that the the the suffix the what [19:02] was the platform is now a suffix that [19:04] matches the first eight digits of the [19:06] check sum. and we move the platform uh [19:10] as to a requirement so we can get that [19:12] information. Still we also scope the [19:16] Ruby requirement to scope to a single [19:19] Ruby API. [19:22] There's one caveat um by doing this [19:25] rename old CL clients of bundler thinks [19:28] this is a platform. So um if older [19:33] clients do install this it'll kind of [19:35] crash out. So this will only be [19:37] available for new clients and we guarded [19:40] against this by uh adding a review gems [19:44] required [19:46] Ruby gems requirement here that only [19:48] scopes to newer clients. [19:52] We added this change to rubygeems.org or [19:55] as well as Ruby Gems and Bundler and it [19:58] the the initial support is a part of for [20:03] Ruby Gems 4.1 beta which was released a [20:07] week or two ago. [20:09] So for gem maintainers uh of native [20:13] extensions, you can push content [20:16] adjustable gems uh with the Ruby API [20:19] option and they'll specify the require [20:23] Ruby version and require Ruby gems [20:25] version. And we're currently updating [20:28] tooling or tool um tools in the tool [20:32] chain to support pushing content [20:34] adjustable gems. So we have a PR up to [20:36] Ray compiler. Um so hopefully in the [20:41] next couple of weeks uh folks that are [20:43] using RI compiler to pre-ompile their [20:46] gems can use [20:49] can um yeah try pushing content [20:51] adjustable gems. [20:53] And if you own a gem that [20:58] if you own a gem that uh has native [21:02] extensions, but they aren't pre-ompiled, [21:05] you should pre-ompile them. uh you can [21:08] try out uh uh CI build gem that Edward [21:13] created and essentially it's a gem that [21:17] helps you create a GitHub workflow and [21:21] uh that will help you pre-ompile per [21:24] platform and push it up to [21:26] rubygeems.org. [21:29] For people that install content [21:31] addressable gems, they will be preferred [21:34] over um preferred over the legacy [21:38] multi-API versions. Uh and you'll see [21:41] them in your gem file.lock in a new [21:45] section. [21:47] You may be thinking, okay, what's the [21:49] impact of all of this? Um why are like [21:52] we can push single AIS, but what's the [21:54] impact? Well, uh I push single AI [21:58] versions of all the gems that are [22:00] pre-ompiled for a new Rails version and [22:04] um it reduces the download size of the [22:07] entire B bundle by 20%. It's okay, but [22:11] the real savings here is that there are [22:14] dozen there like about more than a dozen [22:17] gems that are that have native [22:20] extensions but aren't pre-ompiled. So, [22:23] uh, we're unlocking a lot of future [22:25] savings. [22:27] Cool. So, those are some of the new [22:30] features that are in, uh, have been, um, [22:34] shipped over the past year. And let's [22:36] talk about some future ideas. Uh, the [22:40] first one is related to security like [22:43] uh, cooldowns. These are security [22:45] warnings. It would be great for Bundler [22:47] to help you identify when you're using a [22:49] vulnerable version of a gem. [22:52] and and we can add [22:55] advi we can add that into the compact [22:57] index by uh possibly adding some [23:00] advisory information. [23:04] Another feature that we can add is more [23:07] requirements to pre-ompile gems to [23:10] ensure uh correct compatibility. Right [23:13] now we like Ruby engine information. Um [23:17] there's a bug currently in Ruby gems [23:19] where if you have uh if you're using [23:24] another Ruby implementation like truffle [23:27] Ruby and install um and [23:32] like truffle Ruby C Ruby binaries uh [23:35] could be installed. So we can add the [23:40] engine information so that [23:43] there so that we can compile more [23:47] binaries for different engines. [23:50] Okay, great. So we to conclude we talked [23:54] about the compact index internals and [23:56] how it interacts with bundler some [23:59] recent evolutions to the index and the [24:01] new features in bundler as well as [24:03] future additions uh to the index. Um [24:08] hopefully you can use some of the new [24:10] features like cooldowns and try out uh [24:14] the beta versions of ruby gems.org or [24:17] that will be very helpful to figure out [24:19] bugs and get them solved before the [24:22] stable release get gets released. Uh you [24:25] can take a look at more about all the [24:27] new features uh that are coming uh in [24:30] the release page and um in the coming [24:34] and look out for uh blog posts on these [24:37] new features. Um I'll be posting a blog [24:41] post about content addressable gems [24:43] soon. So, keep out keep an eye out for [24:46] that. Uh, I would like to thank all [24:49] these people that uh helped out with all [24:52] this work. It's been great to work with [24:56] y'all. And yeah, thanks for listening. [24:59] [applause] [25:03] >> [music]